diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 3b07edf5..a26ebfc1 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "0.13.1" + ".": "0.14.0" } \ No newline at end of file diff --git a/.stats.yml b/.stats.yml index 68bc0797..ba76caea 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,2 +1,2 @@ configured_endpoints: 7 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/groqcloud%2Fgroqcloud-a711d22c2283945608fc5ab6a399805da8961d6b9e0e068637d389ed611230c0.yml +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/groqcloud%2Fgroqcloud-33be0d612b9f1153b86f53e95bf7c571af2f1e466bda2330b632e6c05832e2a6.yml diff --git a/CHANGELOG.md b/CHANGELOG.md index 642eec50..7ae962f0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,35 @@ # Changelog +## 0.14.0 (2025-01-09) + +Full Changelog: [v0.13.1...v0.14.0](https://github.com/groq/groq-python/compare/v0.13.1...v0.14.0) + +### Features + +* **api:** api update ([#163](https://github.com/groq/groq-python/issues/163)) ([43a7a5b](https://github.com/groq/groq-python/commit/43a7a5b048b22f4a5edba53ec31b2b8967681708)) +* **api:** api update ([#167](https://github.com/groq/groq-python/issues/167)) ([5016206](https://github.com/groq/groq-python/commit/5016206e461c384806ac3c68b8dfab3d342ba93c)) +* **api:** api update ([#170](https://github.com/groq/groq-python/issues/170)) ([2b35e95](https://github.com/groq/groq-python/commit/2b35e952e12020116adc45e40007c3fd61db1bb7)) + + +### Bug Fixes + +* **client:** only call .close() when needed ([#169](https://github.com/groq/groq-python/issues/169)) ([6a0ec57](https://github.com/groq/groq-python/commit/6a0ec576de707ed90a4a536ff206e9ee07fc5a3a)) + + +### Chores + +* add missing isclass check ([#166](https://github.com/groq/groq-python/issues/166)) ([9cb1e72](https://github.com/groq/groq-python/commit/9cb1e727377c93c92d1bbd49f1c5b8613730c3a6)) +* **internal:** bump httpx dependency ([#168](https://github.com/groq/groq-python/issues/168)) ([c260ae9](https://github.com/groq/groq-python/commit/c260ae969caa5f4e7b48dd558802b933da98bed6)) +* **internal:** codegen related update ([#158](https://github.com/groq/groq-python/issues/158)) ([85b5765](https://github.com/groq/groq-python/commit/85b5765b2b6cfa9560c763600699fd05f7b2a632)) +* **internal:** codegen related update ([#160](https://github.com/groq/groq-python/issues/160)) ([8b87c4d](https://github.com/groq/groq-python/commit/8b87c4d657e0a9d2296323eff6d298ec98b34b3e)) +* **internal:** codegen related update ([#164](https://github.com/groq/groq-python/issues/164)) ([d7b6be5](https://github.com/groq/groq-python/commit/d7b6be5f4bba87002409330644045ba630856880)) +* **internal:** fix some typos ([#162](https://github.com/groq/groq-python/issues/162)) ([32482ae](https://github.com/groq/groq-python/commit/32482ae691f24fdbd5c80282c597a299a48a247d)) + + +### Documentation + +* **readme:** example snippet for client context manager ([#161](https://github.com/groq/groq-python/issues/161)) ([b7bfd15](https://github.com/groq/groq-python/commit/b7bfd15768d60beb2059ab3d326bae1b19c6bf17)) + ## 0.13.1 (2024-12-14) Full Changelog: [v0.13.0...v0.13.1](https://github.com/groq/groq-python/compare/v0.13.0...v0.13.1) diff --git a/LICENSE b/LICENSE index 76a24565..a162f20d 100644 --- a/LICENSE +++ b/LICENSE @@ -186,7 +186,7 @@ same "printed page" as the copyright notice for easier identification within third-party archives. - Copyright 2024 Groq + Copyright 2025 Groq Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/README.md b/README.md index 9c36bbb3..d9c05a20 100644 --- a/README.md +++ b/README.md @@ -363,6 +363,16 @@ client.with_options(http_client=DefaultHttpxClient(...)) By default the library closes underlying HTTP connections whenever the client is [garbage collected](https://docs.python.org/3/reference/datamodel.html#object.__del__). You can manually close the client using the `.close()` method if desired, or with a context manager that closes when exiting. +```py +from groq import Groq + +with Groq() as client: + # make requests here + ... + +# HTTP client is now closed +``` + ## Versioning This package generally follows [SemVer](https://semver.org/spec/v2.0.0.html) conventions, though certain backwards-incompatible changes may be released as minor versions: diff --git a/pyproject.toml b/pyproject.toml index 478101e7..79c81742 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "groq" -version = "0.13.1" +version = "0.14.0" description = "The official Python library for the groq API" dynamic = ["readme"] license = "Apache-2.0" @@ -54,7 +54,7 @@ dev-dependencies = [ "dirty-equals>=0.6.0", "importlib-metadata>=6.7.0", "rich>=13.7.1", - "nest_asyncio==1.6.0" + "nest_asyncio==1.6.0", ] [tool.rye.scripts] diff --git a/requirements-dev.lock b/requirements-dev.lock index 5b05eb3e..94ac99ec 100644 --- a/requirements-dev.lock +++ b/requirements-dev.lock @@ -35,7 +35,7 @@ h11==0.14.0 # via httpcore httpcore==1.0.2 # via httpx -httpx==0.25.2 +httpx==0.28.1 # via groq # via respx idna==3.4 @@ -76,7 +76,7 @@ python-dateutil==2.8.2 # via time-machine pytz==2023.3.post1 # via dirty-equals -respx==0.20.2 +respx==0.22.0 rich==13.7.1 ruff==0.6.9 setuptools==68.2.2 @@ -86,7 +86,6 @@ six==1.16.0 sniffio==1.3.0 # via anyio # via groq - # via httpx time-machine==2.9.0 tomli==2.0.2 # via mypy diff --git a/requirements.lock b/requirements.lock index 3d7e46b8..29d44423 100644 --- a/requirements.lock +++ b/requirements.lock @@ -25,7 +25,7 @@ h11==0.14.0 # via httpcore httpcore==1.0.2 # via httpx -httpx==0.25.2 +httpx==0.28.1 # via groq idna==3.4 # via anyio @@ -37,7 +37,6 @@ pydantic-core==2.27.1 sniffio==1.3.0 # via anyio # via groq - # via httpx typing-extensions==4.12.2 # via anyio # via groq diff --git a/src/groq/_base_client.py b/src/groq/_base_client.py index f4622fbd..c3f36095 100644 --- a/src/groq/_base_client.py +++ b/src/groq/_base_client.py @@ -767,6 +767,9 @@ def __init__(self, **kwargs: Any) -> None: class SyncHttpxClientWrapper(DefaultHttpxClient): def __del__(self) -> None: + if self.is_closed: + return + try: self.close() except Exception: @@ -1334,6 +1337,9 @@ def __init__(self, **kwargs: Any) -> None: class AsyncHttpxClientWrapper(DefaultAsyncHttpxClient): def __del__(self) -> None: + if self.is_closed: + return + try: # TODO(someday): support non asyncio runtimes here asyncio.get_running_loop().create_task(self.aclose()) diff --git a/src/groq/_models.py b/src/groq/_models.py index 7a547ce5..d56ea1d9 100644 --- a/src/groq/_models.py +++ b/src/groq/_models.py @@ -488,7 +488,11 @@ def construct_type(*, value: object, type_: object) -> object: _, items_type = get_args(type_) # Dict[_, items_type] return {key: construct_type(value=item, type_=items_type) for key, item in value.items()} - if not is_literal_type(type_) and (issubclass(origin, BaseModel) or issubclass(origin, GenericModel)): + if ( + not is_literal_type(type_) + and inspect.isclass(origin) + and (issubclass(origin, BaseModel) or issubclass(origin, GenericModel)) + ): if is_list(value): return [cast(Any, type_).construct(**entry) if is_mapping(entry) else entry for entry in value] diff --git a/src/groq/_version.py b/src/groq/_version.py index f48453b6..de78ce10 100644 --- a/src/groq/_version.py +++ b/src/groq/_version.py @@ -1,4 +1,4 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. __title__ = "groq" -__version__ = "0.13.1" # x-release-please-version +__version__ = "0.14.0" # x-release-please-version diff --git a/src/groq/resources/audio/transcriptions.py b/src/groq/resources/audio/transcriptions.py index 1fbbef58..c67d7781 100644 --- a/src/groq/resources/audio/transcriptions.py +++ b/src/groq/resources/audio/transcriptions.py @@ -186,8 +186,7 @@ def create( improve accuracy and latency. prompt: An optional text to guide the model's style or continue a previous audio - segment. The [prompt](/docs/guides/speech-to-text/prompting) should match the - audio language. + segment. The [prompt](/docs/speech-text) should match the audio language. response_format: The format of the transcript output, in one of these options: `json`, `text`, or `verbose_json`. @@ -396,8 +395,7 @@ async def create( improve accuracy and latency. prompt: An optional text to guide the model's style or continue a previous audio - segment. The [prompt](/docs/guides/speech-to-text/prompting) should match the - audio language. + segment. The [prompt](/docs/speech-text) should match the audio language. response_format: The format of the transcript output, in one of these options: `json`, `text`, or `verbose_json`. diff --git a/src/groq/resources/chat/completions.py b/src/groq/resources/chat/completions.py index bcd0117e..94906cf6 100644 --- a/src/groq/resources/chat/completions.py +++ b/src/groq/resources/chat/completions.py @@ -69,6 +69,7 @@ def create( presence_penalty: Optional[float] | NotGiven = NOT_GIVEN, response_format: Optional[completion_create_params.ResponseFormat] | NotGiven = NOT_GIVEN, seed: Optional[int] | NotGiven = NOT_GIVEN, + service_tier: Optional[Literal["auto", "on_demand", "flex"]] | NotGiven = NOT_GIVEN, stop: Union[Optional[str], List[str], None] | NotGiven = NOT_GIVEN, stream: Optional[Literal[False]] | NotGiven = NOT_GIVEN, temperature: Optional[float] | NotGiven = NOT_GIVEN, @@ -103,6 +104,7 @@ def create( presence_penalty: Optional[float] | NotGiven = NOT_GIVEN, response_format: Optional[completion_create_params.ResponseFormat] | NotGiven = NOT_GIVEN, seed: Optional[int] | NotGiven = NOT_GIVEN, + service_tier: Optional[Literal["auto", "on_demand", "flex"]] | NotGiven = NOT_GIVEN, stop: Union[Optional[str], List[str], None] | NotGiven = NOT_GIVEN, stream: Literal[True], temperature: Optional[float] | NotGiven = NOT_GIVEN, @@ -137,6 +139,7 @@ def create( presence_penalty: Optional[float] | NotGiven = NOT_GIVEN, response_format: Optional[completion_create_params.ResponseFormat] | NotGiven = NOT_GIVEN, seed: Optional[int] | NotGiven = NOT_GIVEN, + service_tier: Optional[Literal["auto", "on_demand", "flex"]] | NotGiven = NOT_GIVEN, stop: Union[Optional[str], List[str], None] | NotGiven = NOT_GIVEN, stream: bool, temperature: Optional[float] | NotGiven = NOT_GIVEN, @@ -170,6 +173,7 @@ def create( presence_penalty: Optional[float] | NotGiven = NOT_GIVEN, response_format: Optional[completion_create_params.ResponseFormat] | NotGiven = NOT_GIVEN, seed: Optional[int] | NotGiven = NOT_GIVEN, + service_tier: Optional[Literal["auto", "on_demand", "flex"]] | NotGiven = NOT_GIVEN, stop: Union[Optional[str], List[str], None] | NotGiven = NOT_GIVEN, stream: Optional[Literal[False]] | Literal[True] | NotGiven = NOT_GIVEN, temperature: Optional[float] | NotGiven = NOT_GIVEN, @@ -247,6 +251,12 @@ def create( the same result. Determinism is not guaranteed, and you should refer to the `system_fingerprint` response parameter to monitor changes in the backend. + service_tier: The service tier to use for the request. Defaults to `on_demand`. + + - `auto` will automatically select the highest tier available within the rate + limits of your organization. + - `flex` uses the flex tier, which will succeed or fail quickly. + stop: Up to 4 sequences where the API will stop generating further tokens. The returned text will not contain the stop sequence. @@ -312,6 +322,7 @@ def create( "presence_penalty": presence_penalty, "response_format": response_format, "seed": seed, + "service_tier": service_tier, "stop": stop, "stream": stream, "temperature": temperature, @@ -369,6 +380,7 @@ async def create( presence_penalty: Optional[float] | NotGiven = NOT_GIVEN, response_format: Optional[completion_create_params.ResponseFormat] | NotGiven = NOT_GIVEN, seed: Optional[int] | NotGiven = NOT_GIVEN, + service_tier: Optional[Literal["auto", "on_demand", "flex"]] | NotGiven = NOT_GIVEN, stop: Union[Optional[str], List[str], None] | NotGiven = NOT_GIVEN, stream: Optional[Literal[False]] | NotGiven = NOT_GIVEN, temperature: Optional[float] | NotGiven = NOT_GIVEN, @@ -403,6 +415,7 @@ async def create( presence_penalty: Optional[float] | NotGiven = NOT_GIVEN, response_format: Optional[completion_create_params.ResponseFormat] | NotGiven = NOT_GIVEN, seed: Optional[int] | NotGiven = NOT_GIVEN, + service_tier: Optional[Literal["auto", "on_demand", "flex"]] | NotGiven = NOT_GIVEN, stop: Union[Optional[str], List[str], None] | NotGiven = NOT_GIVEN, stream: Literal[True], temperature: Optional[float] | NotGiven = NOT_GIVEN, @@ -437,6 +450,7 @@ async def create( presence_penalty: Optional[float] | NotGiven = NOT_GIVEN, response_format: Optional[completion_create_params.ResponseFormat] | NotGiven = NOT_GIVEN, seed: Optional[int] | NotGiven = NOT_GIVEN, + service_tier: Optional[Literal["auto", "on_demand", "flex"]] | NotGiven = NOT_GIVEN, stop: Union[Optional[str], List[str], None] | NotGiven = NOT_GIVEN, stream: bool, temperature: Optional[float] | NotGiven = NOT_GIVEN, @@ -470,6 +484,7 @@ async def create( presence_penalty: Optional[float] | NotGiven = NOT_GIVEN, response_format: Optional[completion_create_params.ResponseFormat] | NotGiven = NOT_GIVEN, seed: Optional[int] | NotGiven = NOT_GIVEN, + service_tier: Optional[Literal["auto", "on_demand", "flex"]] | NotGiven = NOT_GIVEN, stop: Union[Optional[str], List[str], None] | NotGiven = NOT_GIVEN, stream: Optional[Literal[False]] | Literal[True] | NotGiven = NOT_GIVEN, temperature: Optional[float] | NotGiven = NOT_GIVEN, @@ -547,6 +562,12 @@ async def create( the same result. Determinism is not guaranteed, and you should refer to the `system_fingerprint` response parameter to monitor changes in the backend. + service_tier: The service tier to use for the request. Defaults to `on_demand`. + + - `auto` will automatically select the highest tier available within the rate + limits of your organization. + - `flex` uses the flex tier, which will succeed or fail quickly. + stop: Up to 4 sequences where the API will stop generating further tokens. The returned text will not contain the stop sequence. @@ -612,6 +633,7 @@ async def create( "presence_penalty": presence_penalty, "response_format": response_format, "seed": seed, + "service_tier": service_tier, "stop": stop, "stream": stream, "temperature": temperature, diff --git a/src/groq/types/audio/transcription_create_params.py b/src/groq/types/audio/transcription_create_params.py index f3000768..0ae47eb0 100644 --- a/src/groq/types/audio/transcription_create_params.py +++ b/src/groq/types/audio/transcription_create_params.py @@ -136,8 +136,7 @@ class TranscriptionCreateParams(TypedDict, total=False): """An optional text to guide the model's style or continue a previous audio segment. - The [prompt](/docs/guides/speech-to-text/prompting) should match the audio - language. + The [prompt](/docs/speech-text) should match the audio language. """ response_format: Literal["json", "text", "verbose_json"] diff --git a/src/groq/types/chat/completion_create_params.py b/src/groq/types/chat/completion_create_params.py index 811c2d15..770578ed 100644 --- a/src/groq/types/chat/completion_create_params.py +++ b/src/groq/types/chat/completion_create_params.py @@ -106,6 +106,14 @@ class CompletionCreateParams(TypedDict, total=False): `system_fingerprint` response parameter to monitor changes in the backend. """ + service_tier: Optional[Literal["auto", "on_demand", "flex"]] + """The service tier to use for the request. Defaults to `on_demand`. + + - `auto` will automatically select the highest tier available within the rate + limits of your organization. + - `flex` uses the flex tier, which will succeed or fail quickly. + """ + stop: Union[Optional[str], List[str], None] """Up to 4 sequences where the API will stop generating further tokens. diff --git a/tests/api_resources/chat/test_completions.py b/tests/api_resources/chat/test_completions.py index f89e3572..f684046d 100644 --- a/tests/api_resources/chat/test_completions.py +++ b/tests/api_resources/chat/test_completions.py @@ -58,6 +58,7 @@ def test_method_create_with_all_params(self, client: Groq) -> None: presence_penalty=-2, response_format={"type": "text"}, seed=0, + service_tier="auto", stop="\n", stream=False, temperature=1, @@ -159,6 +160,7 @@ async def test_method_create_with_all_params(self, async_client: AsyncGroq) -> N presence_penalty=-2, response_format={"type": "text"}, seed=0, + service_tier="auto", stop="\n", stream=False, temperature=1, diff --git a/tests/test_client.py b/tests/test_client.py index 1d86aef5..3e66af69 100644 --- a/tests/test_client.py +++ b/tests/test_client.py @@ -342,11 +342,11 @@ def test_default_query_option(self) -> None: FinalRequestOptions( method="get", url="/foo", - params={"foo": "baz", "query_param": "overriden"}, + params={"foo": "baz", "query_param": "overridden"}, ) ) url = httpx.URL(request.url) - assert dict(url.params) == {"foo": "baz", "query_param": "overriden"} + assert dict(url.params) == {"foo": "baz", "query_param": "overridden"} def test_request_extra_json(self) -> None: request = self.client._build_request( @@ -1158,11 +1158,11 @@ def test_default_query_option(self) -> None: FinalRequestOptions( method="get", url="/foo", - params={"foo": "baz", "query_param": "overriden"}, + params={"foo": "baz", "query_param": "overridden"}, ) ) url = httpx.URL(request.url) - assert dict(url.params) == {"foo": "baz", "query_param": "overriden"} + assert dict(url.params) == {"foo": "baz", "query_param": "overridden"} def test_request_extra_json(self) -> None: request = self.client._build_request(