Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: openai/openai-python
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: v1.11.1
Choose a base ref
...
head repository: openai/openai-python
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: v1.12.0
Choose a head ref
  • 8 commits
  • 31 files changed
  • 1 contributor

Commits on Feb 9, 2024

  1. Copy the full SHA
    489dadf View commit details
  2. Copy the full SHA
    adb0b31 View commit details
  3. Copy the full SHA
    0f09346 View commit details
  4. Copy the full SHA
    2dc3976 View commit details
  5. Copy the full SHA
    a061daf View commit details
  6. Copy the full SHA
    93f3d3c View commit details
  7. Copy the full SHA
    d6f9334 View commit details
  8. release: 1.12.0

    stainless-bot committed Feb 9, 2024
    Copy the full SHA
    7f9e850 View commit details
Showing with 339 additions and 92 deletions.
  1. +1 −1 .release-please-manifest.json
  2. +26 −0 CHANGELOG.md
  3. +125 −0 CONTRIBUTING.md
  4. +5 −1 pyproject.toml
  5. +2 −0 src/openai/_utils/__init__.py
  6. +8 −1 src/openai/_utils/_transform.py
  7. +8 −1 src/openai/_utils/_typing.py
  8. +4 −0 src/openai/_utils/_utils.py
  9. +1 −1 src/openai/_version.py
  10. +9 −0 src/openai/cli/_api/image.py
  11. +13 −1 src/openai/resources/audio/transcriptions.py
  12. +5 −5 src/openai/resources/beta/assistants/assistants.py
  13. +5 −5 src/openai/resources/beta/threads/runs/runs.py
  14. +5 −5 src/openai/resources/beta/threads/threads.py
  15. +39 −31 src/openai/resources/chat/completions.py
  16. +9 −9 src/openai/resources/completions.py
  17. +3 −3 src/openai/resources/embeddings.py
  18. +9 −1 src/openai/types/audio/transcription_create_params.py
  19. +2 −2 src/openai/types/beta/assistant_create_params.py
  20. +2 −2 src/openai/types/beta/assistant_update_params.py
  21. +3 −3 src/openai/types/beta/thread_create_and_run_params.py
  22. +2 −2 src/openai/types/beta/thread_create_params.py
  23. +2 −2 src/openai/types/beta/threads/run_create_params.py
  24. +2 −2 src/openai/types/beta/threads/run_submit_tool_outputs_params.py
  25. +2 −2 src/openai/types/chat/chat_completion_assistant_message_param.py
  26. +2 −2 src/openai/types/chat/chat_completion_user_message_param.py
  27. +6 −5 src/openai/types/chat/completion_create_params.py
  28. +2 −2 src/openai/types/completion_create_params.py
  29. +2 −2 src/openai/types/embedding_create_params.py
  30. +2 −0 tests/api_resources/audio/test_transcriptions.py
  31. +33 −1 tests/test_transform.py
2 changes: 1 addition & 1 deletion .release-please-manifest.json
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
{
".": "1.11.1"
".": "1.12.0"
}
26 changes: 26 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,31 @@
# Changelog

## 1.12.0 (2024-02-08)

Full Changelog: [v1.11.1...v1.12.0](https://github.com/openai/openai-python/compare/v1.11.1...v1.12.0)

### Features

* **api:** add `timestamp_granularities`, add `gpt-3.5-turbo-0125` model ([#1125](https://github.com/openai/openai-python/issues/1125)) ([1ecf8f6](https://github.com/openai/openai-python/commit/1ecf8f6b12323ed09fb6a2815c85b9533ee52a50))
* **cli/images:** add support for `--model` arg ([#1132](https://github.com/openai/openai-python/issues/1132)) ([0d53866](https://github.com/openai/openai-python/commit/0d5386615cda7cd50d5db90de2119b84dba29519))


### Bug Fixes

* remove double brackets from timestamp_granularities param ([#1140](https://github.com/openai/openai-python/issues/1140)) ([3db0222](https://github.com/openai/openai-python/commit/3db022216a81fa86470b53ec1246669bc7b17897))
* **types:** loosen most List params types to Iterable ([#1129](https://github.com/openai/openai-python/issues/1129)) ([bdb31a3](https://github.com/openai/openai-python/commit/bdb31a3b1db6ede4e02b3c951c4fd23f70260038))


### Chores

* **internal:** add lint command ([#1128](https://github.com/openai/openai-python/issues/1128)) ([4c021c0](https://github.com/openai/openai-python/commit/4c021c0ab0151c2ec092d860c9b60e22e658cd03))
* **internal:** support serialising iterable types ([#1127](https://github.com/openai/openai-python/issues/1127)) ([98d4e59](https://github.com/openai/openai-python/commit/98d4e59afcf2d65d4e660d91eb9462240ef5cd63))


### Documentation

* add CONTRIBUTING.md ([#1138](https://github.com/openai/openai-python/issues/1138)) ([79c8f0e](https://github.com/openai/openai-python/commit/79c8f0e8bf5470e2e31e781e8d279331e89ddfbe))

## 1.11.1 (2024-02-04)

Full Changelog: [v1.11.0...v1.11.1](https://github.com/openai/openai-python/compare/v1.11.0...v1.11.1)
125 changes: 125 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
## Setting up the environment

### With Rye

We use [Rye](https://rye-up.com/) to manage dependencies so we highly recommend [installing it](https://rye-up.com/guide/installation/) as it will automatically provision a Python environment with the expected Python version.

After installing Rye, you'll just have to run this command:

```sh
$ rye sync --all-features
```

You can then run scripts using `rye run python script.py` or by activating the virtual environment:

```sh
$ rye shell
# or manually activate - https://docs.python.org/3/library/venv.html#how-venvs-work
$ source .venv/bin/activate

# now you can omit the `rye run` prefix
$ python script.py
```

### Without Rye

Alternatively if you don't want to install `Rye`, you can stick with the standard `pip` setup by ensuring you have the Python version specified in `.python-version`, create a virtual environment however you desire and then install dependencies using this command:

```sh
$ pip install -r requirements-dev.lock
```

## Modifying/Adding code

Most of the SDK is generated code, and any modified code will be overridden on the next generation. The
`src/openai/lib/` and `examples/` directories are exceptions and will never be overridden.

## Adding and running examples

All files in the `examples/` directory are not modified by the Stainless generator and can be freely edited or
added to.

```bash
# add an example to examples/<your-example>.py

#!/usr/bin/env -S rye run python
```

```
chmod +x examples/<your-example>.py
# run the example against your api
./examples/<your-example>.py
```

## Using the repository from source

If you’d like to use the repository from source, you can either install from git or link to a cloned repository:

To install via git:

```bash
pip install git+ssh://git@github.com:openai/openai-python.git
```

Alternatively, you can build from source and install the wheel file:

Building this package will create two files in the `dist/` directory, a `.tar.gz` containing the source files and a `.whl` that can be used to install the package efficiently.

To create a distributable version of the library, all you have to do is run this command:

```bash
rye build
# or
python -m build
```

Then to install:

```sh
pip install ./path-to-wheel-file.whl
```

## Running tests

Most tests will require you to [setup a mock server](https://github.com/stoplightio/prism) against the OpenAPI spec to run the tests.

```bash
# you will need npm installed
npx prism path/to/your/openapi.yml
```

```bash
rye run pytest
```

## Linting and formatting

This repository uses [ruff](https://github.com/astral-sh/ruff) and
[black](https://github.com/psf/black) to format the code in the repository.

To lint:

```bash
rye run lint
```

To format and fix all ruff issues automatically:

```bash
rye run format
```

## Publishing and releases

Changes made to this repository via the automated release PR pipeline should publish to PyPI automatically. If
the changes aren't made through the automated pipeline, you may want to make releases manually.

### Publish with a GitHub workflow

You can release to package managers by using [the `Publish PyPI` GitHub action](https://www.github.com/openai/openai-python/actions/workflows/publish-pypi.yml). This will require a setup organization or repository secret to be set up.

### Publish manually

If you need to manually release a package, you can run the `bin/publish-pypi` script with an `PYPI_TOKEN` set on
the environment.
6 changes: 5 additions & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[project]
name = "openai"
version = "1.11.1"
version = "1.12.0"
description = "The official Python library for the openai API"
readme = "README.md"
license = "Apache-2.0"
@@ -75,6 +75,10 @@ format = { chain = [
"format:ruff" = "ruff format"
"format:isort" = "isort ."

"lint" = { chain = [
"check:ruff",
"typecheck",
]}
"check:ruff" = "ruff ."
"fix:ruff" = "ruff --fix ."

2 changes: 2 additions & 0 deletions src/openai/_utils/__init__.py
Original file line number Diff line number Diff line change
@@ -9,6 +9,7 @@
is_mapping as is_mapping,
is_tuple_t as is_tuple_t,
parse_date as parse_date,
is_iterable as is_iterable,
is_sequence as is_sequence,
coerce_float as coerce_float,
is_mapping_t as is_mapping_t,
@@ -33,6 +34,7 @@
is_list_type as is_list_type,
is_union_type as is_union_type,
extract_type_arg as extract_type_arg,
is_iterable_type as is_iterable_type,
is_required_type as is_required_type,
is_annotated_type as is_annotated_type,
strip_annotated_type as strip_annotated_type,
9 changes: 8 additions & 1 deletion src/openai/_utils/_transform.py
Original file line number Diff line number Diff line change
@@ -9,11 +9,13 @@
from ._utils import (
is_list,
is_mapping,
is_iterable,
)
from ._typing import (
is_list_type,
is_union_type,
extract_type_arg,
is_iterable_type,
is_required_type,
is_annotated_type,
strip_annotated_type,
@@ -157,7 +159,12 @@ def _transform_recursive(
if is_typeddict(stripped_type) and is_mapping(data):
return _transform_typeddict(data, stripped_type)

if is_list_type(stripped_type) and is_list(data):
if (
# List[T]
(is_list_type(stripped_type) and is_list(data))
# Iterable[T]
or (is_iterable_type(stripped_type) and is_iterable(data) and not isinstance(data, str))
):
inner_type = extract_type_arg(stripped_type, 0)
return [_transform_recursive(d, annotation=annotation, inner_type=inner_type) for d in data]

9 changes: 8 additions & 1 deletion src/openai/_utils/_typing.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
from __future__ import annotations

from typing import Any, TypeVar, cast
from typing import Any, TypeVar, Iterable, cast
from collections import abc as _c_abc
from typing_extensions import Required, Annotated, get_args, get_origin

from .._types import InheritsGeneric
@@ -15,6 +16,12 @@ def is_list_type(typ: type) -> bool:
return (get_origin(typ) or typ) == list


def is_iterable_type(typ: type) -> bool:
"""If the given type is `typing.Iterable[T]`"""
origin = get_origin(typ) or typ
return origin == Iterable or origin == _c_abc.Iterable


def is_union_type(typ: type) -> bool:
return _is_union(get_origin(typ))

4 changes: 4 additions & 0 deletions src/openai/_utils/_utils.py
Original file line number Diff line number Diff line change
@@ -164,6 +164,10 @@ def is_list(obj: object) -> TypeGuard[list[object]]:
return isinstance(obj, list)


def is_iterable(obj: object) -> TypeGuard[Iterable[object]]:
return isinstance(obj, Iterable)


def deepcopy_minimal(item: _T) -> _T:
"""Minimal reimplementation of copy.deepcopy() that will only copy certain object types:
2 changes: 1 addition & 1 deletion src/openai/_version.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# File generated from our OpenAPI spec by Stainless.

__title__ = "openai"
__version__ = "1.11.1" # x-release-please-version
__version__ = "1.12.0" # x-release-please-version
9 changes: 9 additions & 0 deletions src/openai/cli/_api/image.py
Original file line number Diff line number Diff line change
@@ -14,13 +14,15 @@

def register(subparser: _SubParsersAction[ArgumentParser]) -> None:
sub = subparser.add_parser("images.generate")
sub.add_argument("-m", "--model", type=str)
sub.add_argument("-p", "--prompt", type=str, required=True)
sub.add_argument("-n", "--num-images", type=int, default=1)
sub.add_argument("-s", "--size", type=str, default="1024x1024", help="Size of the output image")
sub.add_argument("--response-format", type=str, default="url")
sub.set_defaults(func=CLIImage.create, args_model=CLIImageCreateArgs)

sub = subparser.add_parser("images.edit")
sub.add_argument("-m", "--model", type=str)
sub.add_argument("-p", "--prompt", type=str, required=True)
sub.add_argument("-n", "--num-images", type=int, default=1)
sub.add_argument(
@@ -42,6 +44,7 @@ def register(subparser: _SubParsersAction[ArgumentParser]) -> None:
sub.set_defaults(func=CLIImage.edit, args_model=CLIImageEditArgs)

sub = subparser.add_parser("images.create_variation")
sub.add_argument("-m", "--model", type=str)
sub.add_argument("-n", "--num-images", type=int, default=1)
sub.add_argument(
"-I",
@@ -60,13 +63,15 @@ class CLIImageCreateArgs(BaseModel):
num_images: int
size: str
response_format: str
model: NotGivenOr[str] = NOT_GIVEN


class CLIImageCreateVariationArgs(BaseModel):
image: str
num_images: int
size: str
response_format: str
model: NotGivenOr[str] = NOT_GIVEN


class CLIImageEditArgs(BaseModel):
@@ -76,12 +81,14 @@ class CLIImageEditArgs(BaseModel):
response_format: str
prompt: str
mask: NotGivenOr[str] = NOT_GIVEN
model: NotGivenOr[str] = NOT_GIVEN


class CLIImage:
@staticmethod
def create(args: CLIImageCreateArgs) -> None:
image = get_client().images.generate(
model=args.model,
prompt=args.prompt,
n=args.num_images,
# casts required because the API is typed for enums
@@ -97,6 +104,7 @@ def create_variation(args: CLIImageCreateVariationArgs) -> None:
buffer_reader = BufferReader(file_reader.read(), desc="Upload progress")

image = get_client().images.create_variation(
model=args.model,
image=("image", buffer_reader),
n=args.num_images,
# casts required because the API is typed for enums
@@ -118,6 +126,7 @@ def edit(args: CLIImageEditArgs) -> None:
mask = BufferReader(file_reader.read(), desc="Mask progress")

image = get_client().images.edit(
model=args.model,
prompt=args.prompt,
image=("image", buffer_reader),
n=args.num_images,
14 changes: 13 additions & 1 deletion src/openai/resources/audio/transcriptions.py
Original file line number Diff line number Diff line change
@@ -2,7 +2,7 @@

from __future__ import annotations

from typing import Union, Mapping, cast
from typing import List, Union, Mapping, cast
from typing_extensions import Literal

import httpx
@@ -39,6 +39,7 @@ def create(
prompt: str | NotGiven = NOT_GIVEN,
response_format: Literal["json", "text", "srt", "verbose_json", "vtt"] | NotGiven = NOT_GIVEN,
temperature: float | NotGiven = NOT_GIVEN,
timestamp_granularities: List[Literal["word", "segment"]] | NotGiven = NOT_GIVEN,
# Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
# The extra values given here take precedence over values defined on the client or passed to this method.
extra_headers: Headers | None = None,
@@ -74,6 +75,10 @@ def create(
[log probability](https://en.wikipedia.org/wiki/Log_probability) to
automatically increase the temperature until certain thresholds are hit.
timestamp_granularities: The timestamp granularities to populate for this transcription. Any of these
options: `word`, or `segment`. Note: There is no additional latency for segment
timestamps, but generating word timestamps incurs additional latency.
extra_headers: Send extra headers
extra_query: Add additional query parameters to the request
@@ -90,6 +95,7 @@ def create(
"prompt": prompt,
"response_format": response_format,
"temperature": temperature,
"timestamp_granularities": timestamp_granularities,
}
)
files = extract_files(cast(Mapping[str, object], body), paths=[["file"]])
@@ -127,6 +133,7 @@ async def create(
prompt: str | NotGiven = NOT_GIVEN,
response_format: Literal["json", "text", "srt", "verbose_json", "vtt"] | NotGiven = NOT_GIVEN,
temperature: float | NotGiven = NOT_GIVEN,
timestamp_granularities: List[Literal["word", "segment"]] | NotGiven = NOT_GIVEN,
# Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
# The extra values given here take precedence over values defined on the client or passed to this method.
extra_headers: Headers | None = None,
@@ -162,6 +169,10 @@ async def create(
[log probability](https://en.wikipedia.org/wiki/Log_probability) to
automatically increase the temperature until certain thresholds are hit.
timestamp_granularities: The timestamp granularities to populate for this transcription. Any of these
options: `word`, or `segment`. Note: There is no additional latency for segment
timestamps, but generating word timestamps incurs additional latency.
extra_headers: Send extra headers
extra_query: Add additional query parameters to the request
@@ -178,6 +189,7 @@ async def create(
"prompt": prompt,
"response_format": response_format,
"temperature": temperature,
"timestamp_granularities": timestamp_granularities,
}
)
files = extract_files(cast(Mapping[str, object], body), paths=[["file"]])
Loading