Skip to content

Commit aa6d8b1

Browse files
release: 0.31.0 (#248)
Co-authored-by: stainless-app[bot] <142633134+stainless-app[bot]@users.noreply.github.com> Co-authored-by: Graden Rea <[email protected]>
1 parent c7d9156 commit aa6d8b1

20 files changed

+188
-71
lines changed

.gitignore

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
.prism.log
2-
.vscode
32
_dev
43

54
__pycache__

.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.30.0"
2+
".": "0.31.0"
33
}

.stats.yml

Lines changed: 2 additions & 2 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-f687d041a4a85f21b5f6a9fe6592ca87a031aeae448c535bad1bee61114f7818.yml
3-
openapi_spec_hash: f4d39fb37c4e890c8e1e4fc182d7c50a
2+
openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/groqcloud%2Fgroqcloud-4543b558a0a546fc45d3300535b9b535f9cf251f4284bc255d3bc337727e5a50.yml
3+
openapi_spec_hash: 09235cb11f84f84a07819c2b3f0a6d6a
44
config_hash: 6b1c374dcc1ffa3165dd22f52a77ff89

.vscode/settings.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{
2+
"python.analysis.importFormat": "relative",
3+
}

CHANGELOG.md

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

3+
## 0.31.0 (2025-08-05)
4+
5+
Full Changelog: [v0.30.0...v0.31.0](https://github.com/groq/groq-python/compare/v0.30.0...v0.31.0)
6+
7+
### Features
8+
9+
* **api:** api update ([be81724](https://github.com/groq/groq-python/commit/be81724579d5538d340fe4f1bce9ab787ef2e387))
10+
* **api:** api update ([bd9eafd](https://github.com/groq/groq-python/commit/bd9eafd4ef5ff1379c4a716fef023fbacfe0641e))
11+
* **api:** api update ([86eab4f](https://github.com/groq/groq-python/commit/86eab4f85c8e515cd54dfd163d694237f2d6f118))
12+
* **api:** api update ([4068695](https://github.com/groq/groq-python/commit/4068695a917367872432d6b35985692c87dd8faa))
13+
* **api:** api update ([5c45441](https://github.com/groq/groq-python/commit/5c45441126fa94690e4fcbeab497d2c07cf54e50))
14+
* **api:** api update ([30646f2](https://github.com/groq/groq-python/commit/30646f2f85dd6cf328b61628d2c9dac970299d28))
15+
* **api:** api update ([e8ede14](https://github.com/groq/groq-python/commit/e8ede14f50b999ebc9d39da2881f7f59c3aa8b4a))
16+
* **api:** api update ([3c06879](https://github.com/groq/groq-python/commit/3c068790ee3632a58f8da9cfb45d1055b8ac9058))
17+
* **api:** api update ([455c74a](https://github.com/groq/groq-python/commit/455c74a13f0552b9e9abc08a8ddcf40b34a654cc))
18+
* clean up environment call outs ([0627bc6](https://github.com/groq/groq-python/commit/0627bc60fd9c038ae47e63a1bf3a36557157ed9e))
19+
* **client:** support file upload requests ([0f2d5a7](https://github.com/groq/groq-python/commit/0f2d5a78551a91aedd44160126ec85b833a7682b))
20+
21+
22+
### Bug Fixes
23+
24+
* **client:** don't send Content-Type header on GET requests ([7439911](https://github.com/groq/groq-python/commit/74399119e020f45a154f5cdf46bdd63b476090e9))
25+
* **parsing:** ignore empty metadata ([eccd423](https://github.com/groq/groq-python/commit/eccd42322df3347194b64688f222518b56acb7f9))
26+
* **parsing:** parse extra field types ([590a947](https://github.com/groq/groq-python/commit/590a947ec17aca23ce82f546ee9c25800a7061ff))
27+
* streaming overrides ([ff828d6](https://github.com/groq/groq-python/commit/ff828d6363fae6b401dd47e696e7a2380226e051))
28+
29+
30+
### Chores
31+
32+
* **project:** add settings file for vscode ([938789a](https://github.com/groq/groq-python/commit/938789a2545daec2fd9eb5b0c0d612f2aac6419b))
33+
334
## 0.30.0 (2025-07-11)
435

536
Full Changelog: [v0.29.0...v0.30.0](https://github.com/groq/groq-python/compare/v0.29.0...v0.30.0)

README.md

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -95,15 +95,14 @@ pip install groq[aiohttp]
9595
Then you can enable it by instantiating the client with `http_client=DefaultAioHttpClient()`:
9696

9797
```python
98-
import os
9998
import asyncio
10099
from groq import DefaultAioHttpClient
101100
from groq import AsyncGroq
102101

103102

104103
async def main() -> None:
105104
async with AsyncGroq(
106-
api_key=os.environ.get("GROQ_API_KEY"), # This is the default and can be omitted
105+
api_key="My API Key",
107106
http_client=DefaultAioHttpClient(),
108107
) as client:
109108
chat_completion = await client.chat.completions.create(

pyproject.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[project]
22
name = "groq"
3-
version = "0.30.0"
3+
version = "0.31.0"
44
description = "The official Python library for the groq API"
55
dynamic = ["readme"]
66
license = "Apache-2.0"
@@ -39,7 +39,7 @@ Homepage = "https://github.com/groq/groq-python"
3939
Repository = "https://github.com/groq/groq-python"
4040

4141
[project.optional-dependencies]
42-
aiohttp = ["aiohttp", "httpx_aiohttp>=0.1.6"]
42+
aiohttp = ["aiohttp", "httpx_aiohttp>=0.1.8"]
4343

4444
[tool.rye]
4545
managed = true

src/groq/_base_client.py

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -529,6 +529,18 @@ def _build_request(
529529
# work around https://github.com/encode/httpx/discussions/2880
530530
kwargs["extensions"] = {"sni_hostname": prepared_url.host.replace("_", "-")}
531531

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+
532544
# TODO: report this error to httpx
533545
return self._client.build_request( # pyright: ignore[reportUnknownMemberType]
534546
headers=headers,
@@ -540,8 +552,6 @@ def _build_request(
540552
# so that passing a `TypedDict` doesn't cause an error.
541553
# https://github.com/microsoft/pyright/issues/3526#event-6715453066
542554
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,
545555
**kwargs,
546556
)
547557

src/groq/_files.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -69,12 +69,12 @@ def _transform_file(file: FileTypes) -> HttpxFileTypes:
6969
return file
7070

7171
if is_tuple_t(file):
72-
return (file[0], _read_file_content(file[1]), *file[2:])
72+
return (file[0], read_file_content(file[1]), *file[2:])
7373

7474
raise TypeError(f"Expected file types input to be a FileContent type or to be a tuple")
7575

7676

77-
def _read_file_content(file: FileContent) -> HttpxFileContent:
77+
def read_file_content(file: FileContent) -> HttpxFileContent:
7878
if isinstance(file, os.PathLike):
7979
return pathlib.Path(file).read_bytes()
8080
return file
@@ -111,12 +111,12 @@ async def _async_transform_file(file: FileTypes) -> HttpxFileTypes:
111111
return file
112112

113113
if is_tuple_t(file):
114-
return (file[0], await _async_read_file_content(file[1]), *file[2:])
114+
return (file[0], await async_read_file_content(file[1]), *file[2:])
115115

116116
raise TypeError(f"Expected file types input to be a FileContent type or to be a tuple")
117117

118118

119-
async def _async_read_file_content(file: FileContent) -> HttpxFileContent:
119+
async def async_read_file_content(file: FileContent) -> HttpxFileContent:
120120
if isinstance(file, os.PathLike):
121121
return await anyio.Path(file).read_bytes()
122122

src/groq/_models.py

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -208,14 +208,18 @@ def construct( # pyright: ignore[reportIncompatibleMethodOverride]
208208
else:
209209
fields_values[name] = field_get_default(field)
210210

211+
extra_field_type = _get_extra_fields_type(__cls)
212+
211213
_extra = {}
212214
for key, value in values.items():
213215
if key not in model_fields:
216+
parsed = construct_type(value=value, type_=extra_field_type) if extra_field_type is not None else value
217+
214218
if PYDANTIC_V2:
215-
_extra[key] = value
219+
_extra[key] = parsed
216220
else:
217221
_fields_set.add(key)
218-
fields_values[key] = value
222+
fields_values[key] = parsed
219223

220224
object.__setattr__(m, "__dict__", fields_values)
221225

@@ -370,6 +374,23 @@ def _construct_field(value: object, field: FieldInfo, key: str) -> object:
370374
return construct_type(value=value, type_=type_, metadata=getattr(field, "metadata", None))
371375

372376

377+
def _get_extra_fields_type(cls: type[pydantic.BaseModel]) -> type | None:
378+
if not PYDANTIC_V2:
379+
# TODO
380+
return None
381+
382+
schema = cls.__pydantic_core_schema__
383+
if schema["type"] == "model":
384+
fields = schema["schema"]
385+
if fields["type"] == "model-fields":
386+
extras = fields.get("extras_schema")
387+
if extras and "cls" in extras:
388+
# mypy can't narrow the type
389+
return extras["cls"] # type: ignore[no-any-return]
390+
391+
return None
392+
393+
373394
def is_basemodel(type_: type) -> bool:
374395
"""Returns whether or not the given type is either a `BaseModel` or a union of `BaseModel`"""
375396
if is_union(type_):
@@ -439,7 +460,7 @@ def construct_type(*, value: object, type_: object, metadata: Optional[List[Any]
439460
type_ = type_.__value__ # type: ignore[unreachable]
440461

441462
# unwrap `Annotated[T, ...]` -> `T`
442-
if metadata is not None:
463+
if metadata is not None and len(metadata) > 0:
443464
meta: tuple[Any, ...] = tuple(metadata)
444465
elif is_annotated_type(type_):
445466
meta = get_args(type_)[1:]

0 commit comments

Comments
 (0)