Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

release: 0.40.0 #737

Merged
merged 17 commits into from
Nov 28, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 0 additions & 25 deletions .github/workflows/handle-release-pr-title-edit.yml

This file was deleted.

2 changes: 1 addition & 1 deletion .release-please-manifest.json
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
{
".": "0.39.0"
".": "0.40.0"
}
2 changes: 1 addition & 1 deletion .stats.yml
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
configured_endpoints: 10
openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/anthropic-25f83d91f601c1962b3701fedf829f678f306aca0758af286ee1586cc9931f75.yml
openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/anthropic-cf96271afd65b396dc71c4e897d1d55a9526c122e3890bc87b5ff33316c93853.yml
35 changes: 35 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,40 @@
# Changelog

## 0.40.0 (2024-11-28)

Full Changelog: [v0.39.0...v0.40.0](https://github.com/anthropics/anthropic-sdk-python/compare/v0.39.0...v0.40.0)

### Features

* **client:** add ._request_id property to object responses ([#743](https://github.com/anthropics/anthropic-sdk-python/issues/743)) ([9fb64a6](https://github.com/anthropics/anthropic-sdk-python/commit/9fb64a627821730fcf48662f6326d4c0f8c623ab))


### Bug Fixes

* **asyncify:** avoid hanging process under certain conditions ([#756](https://github.com/anthropics/anthropic-sdk-python/issues/756)) ([c71bba2](https://github.com/anthropics/anthropic-sdk-python/commit/c71bba2ad5248400c0142fca5e53c505f9e6d417))
* **bedrock:** correct URL encoding for model params ([#759](https://github.com/anthropics/anthropic-sdk-python/issues/759)) ([be4e73a](https://github.com/anthropics/anthropic-sdk-python/commit/be4e73a6d6ced33c887cc338c7755f5fe1697e54))
* **client:** compat with new httpx 0.28.0 release ([#765](https://github.com/anthropics/anthropic-sdk-python/issues/765)) ([de51f60](https://github.com/anthropics/anthropic-sdk-python/commit/de51f6089f7b025db5d150438caf78a615431cde))
* don't use dicts as iterables in transform ([#750](https://github.com/anthropics/anthropic-sdk-python/issues/750)) ([1f71464](https://github.com/anthropics/anthropic-sdk-python/commit/1f71464a818066687bf6c1bcae0abb991d6ed9cd))
* **types:** remove anthropic-instant-1.2 model ([#744](https://github.com/anthropics/anthropic-sdk-python/issues/744)) ([23637de](https://github.com/anthropics/anthropic-sdk-python/commit/23637de028c6c870f062fc0fbaefa9ae54a0e053))


### Chores

* **api:** update spec version ([#751](https://github.com/anthropics/anthropic-sdk-python/issues/751)) ([4ec986c](https://github.com/anthropics/anthropic-sdk-python/commit/4ec986ccfa601a78f9fff721710390c1fb4727cc))
* **ci:** remove unneeded workflow ([#742](https://github.com/anthropics/anthropic-sdk-python/issues/742)) ([472b7d3](https://github.com/anthropics/anthropic-sdk-python/commit/472b7d362c4bd32e7b32c5a10ed3d40e6821f052))
* **internal:** exclude mypy from running on tests ([#764](https://github.com/anthropics/anthropic-sdk-python/issues/764)) ([bce763a](https://github.com/anthropics/anthropic-sdk-python/commit/bce763a35f5420d0e811ff3cd4d2bf7494f11081))
* **internal:** fix compat model_dump method when warnings are passed ([#760](https://github.com/anthropics/anthropic-sdk-python/issues/760)) ([0e09236](https://github.com/anthropics/anthropic-sdk-python/commit/0e0923612bb1ce4eb18f82966055df4fb8cd348d))
* **internal:** minor formatting changes ([493020e](https://github.com/anthropics/anthropic-sdk-python/commit/493020eed859bd20e49f4ac7ec0b6c3293c7d3fd))
* remove now unused `cached-property` dep ([#762](https://github.com/anthropics/anthropic-sdk-python/issues/762)) ([b9ffefe](https://github.com/anthropics/anthropic-sdk-python/commit/b9ffefec20279705a86e4ad342597886bd7064ca))
* **tests:** adjust retry timeout values ([#736](https://github.com/anthropics/anthropic-sdk-python/issues/736)) ([27ed781](https://github.com/anthropics/anthropic-sdk-python/commit/27ed7816aa8ae32f179652ea6171dd621ef8a6b5))
* **tests:** limit array example length ([#754](https://github.com/anthropics/anthropic-sdk-python/issues/754)) ([6cab2b9](https://github.com/anthropics/anthropic-sdk-python/commit/6cab2b9237c9679ce40e319d035fb4267bca03a7))


### Documentation

* add info log level to readme ([#761](https://github.com/anthropics/anthropic-sdk-python/issues/761)) ([5966b85](https://github.com/anthropics/anthropic-sdk-python/commit/5966b855f3e58d735d8ccfe3244f549baa3a87ed))
* move comments in example snippets ([#749](https://github.com/anthropics/anthropic-sdk-python/issues/749)) ([f887930](https://github.com/anthropics/anthropic-sdk-python/commit/f887930773cbb2d5cb0d4d46ec6cd4f320d045ea))

## 0.39.0 (2024-11-04)

Full Changelog: [v0.38.0...v0.39.0](https://github.com/anthropics/anthropic-sdk-python/compare/v0.38.0...v0.39.0)
Expand Down
36 changes: 30 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,7 @@ import os
from anthropic import Anthropic

client = Anthropic(
# This is the default and can be omitted
api_key=os.environ.get("ANTHROPIC_API_KEY"),
api_key=os.environ.get("ANTHROPIC_API_KEY"), # This is the default and can be omitted
)

message = client.messages.create(
Expand Down Expand Up @@ -58,8 +57,7 @@ import asyncio
from anthropic import AsyncAnthropic

client = AsyncAnthropic(
# This is the default and can be omitted
api_key=os.environ.get("ANTHROPIC_API_KEY"),
api_key=os.environ.get("ANTHROPIC_API_KEY"), # This is the default and can be omitted
)


Expand Down Expand Up @@ -427,6 +425,30 @@ Error codes are as followed:
| >=500 | `InternalServerError` |
| N/A | `APIConnectionError` |

## Request IDs

> For more information on debugging requests, see [these docs](https://docs.anthropic.com/en/api/errors#request-id)

All object responses in the SDK provide a `_request_id` property which is added from the `request-id` response header so that you can quickly log failing requests and report them back to Anthropic.

```python
message = client.messages.create(
max_tokens=1024,
messages=[
{
"role": "user",
"content": "Hello, Claude",
}
],
model="claude-3-opus-20240229",
)
print(message._request_id) # req_018EeWyXxfu5pfWkrYcMdjWG
```

Note that unlike other properties that use an `_` prefix, the `_request_id` property
*is* public. Unless documented otherwise, *all* other `_` prefix properties,
methods and modules are *private*.

### Retries

Certain errors are automatically retried 2 times by default, with a short exponential backoff.
Expand Down Expand Up @@ -515,12 +537,14 @@ client = Anthropic(

We use the standard library [`logging`](https://docs.python.org/3/library/logging.html) module.

You can enable logging by setting the environment variable `ANTHROPIC_LOG` to `debug`.
You can enable logging by setting the environment variable `ANTHROPIC_LOG` to `info`.

```shell
$ export ANTHROPIC_LOG=debug
$ export ANTHROPIC_LOG=info
```

Or to `debug` for more verbose logging.

### How to tell whether `None` means `null` or missing

In an API response, a field may be explicitly `null`, or missing entirely; in either case, its value is `None` in this library. You can differentiate the two cases with `.model_fields_set`:
Expand Down
1 change: 1 addition & 0 deletions api.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ Types:
from anthropic.types import (
ContentBlock,
ContentBlockDeltaEvent,
ContentBlockParam,
ContentBlockStartEvent,
ContentBlockStopEvent,
ImageBlockParam,
Expand Down
5 changes: 4 additions & 1 deletion mypy.ini
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,10 @@ show_error_codes = True
# Exclude _files.py because mypy isn't smart enough to apply
# the correct type narrowing and as this is an internal module
# it's fine to just use Pyright.
exclude = ^(src/anthropic/_files\.py|_dev/.*\.py)$
#
# We also exclude our `tests` as mypy doesn't always infer
# types correctly and Pyright will still catch any type errors.
exclude = ^(src/anthropic/_files\.py|_dev/.*\.py|tests/.*)$

strict_equality = True
implicit_reexport = True
Expand Down
4 changes: 2 additions & 2 deletions pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[project]
name = "anthropic"
version = "0.39.0"
version = "0.40.0"
description = "The official Python library for the anthropic API"
dynamic = ["readme"]
license = "MIT"
Expand All @@ -14,7 +14,6 @@ dependencies = [
"anyio>=3.5.0, <5",
"distro>=1.7.0, <2",
"sniffio",
"cached-property; python_version < '3.8'",
"jiter>=0.4.0, <1",
]
requires-python = ">= 3.8"
Expand Down Expand Up @@ -61,6 +60,7 @@ dev-dependencies = [
"importlib-metadata>=6.7.0",
"boto3-stubs >= 1",
"rich>=13.7.1",
"nest_asyncio==1.6.0"
]

[tool.rye.scripts]
Expand Down
1 change: 1 addition & 0 deletions requirements-dev.lock
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ mdurl==0.1.2
mypy==1.13.0
mypy-extensions==1.0.0
# via mypy
nest-asyncio==1.6.0
nodeenv==1.8.0
# via pyright
nox==2023.4.22
Expand Down
12 changes: 8 additions & 4 deletions src/anthropic/_base_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -793,6 +793,7 @@ def __init__(
custom_query: Mapping[str, object] | None = None,
_strict_response_validation: bool,
) -> None:
kwargs: dict[str, Any] = {}
if limits is not None:
warnings.warn(
"The `connection_pool_limits` argument is deprecated. The `http_client` argument should be passed instead",
Expand All @@ -805,6 +806,7 @@ def __init__(
limits = DEFAULT_CONNECTION_LIMITS

if transport is not None:
kwargs["transport"] = transport
warnings.warn(
"The `transport` argument is deprecated. The `http_client` argument should be passed instead",
category=DeprecationWarning,
Expand All @@ -814,6 +816,7 @@ def __init__(
raise ValueError("The `http_client` argument is mutually exclusive with `transport`")

if proxies is not None:
kwargs["proxies"] = proxies
warnings.warn(
"The `proxies` argument is deprecated. The `http_client` argument should be passed instead",
category=DeprecationWarning,
Expand Down Expand Up @@ -857,10 +860,9 @@ def __init__(
base_url=base_url,
# cast to a valid type because mypy doesn't understand our type narrowing
timeout=cast(Timeout, timeout),
proxies=proxies,
transport=transport,
limits=limits,
follow_redirects=True,
**kwargs, # type: ignore
)

def is_closed(self) -> bool:
Expand Down Expand Up @@ -1374,6 +1376,7 @@ def __init__(
custom_headers: Mapping[str, str] | None = None,
custom_query: Mapping[str, object] | None = None,
) -> None:
kwargs: dict[str, Any] = {}
if limits is not None:
warnings.warn(
"The `connection_pool_limits` argument is deprecated. The `http_client` argument should be passed instead",
Expand All @@ -1386,6 +1389,7 @@ def __init__(
limits = DEFAULT_CONNECTION_LIMITS

if transport is not None:
kwargs["transport"] = transport
warnings.warn(
"The `transport` argument is deprecated. The `http_client` argument should be passed instead",
category=DeprecationWarning,
Expand All @@ -1395,6 +1399,7 @@ def __init__(
raise ValueError("The `http_client` argument is mutually exclusive with `transport`")

if proxies is not None:
kwargs["proxies"] = proxies
warnings.warn(
"The `proxies` argument is deprecated. The `http_client` argument should be passed instead",
category=DeprecationWarning,
Expand Down Expand Up @@ -1438,10 +1443,9 @@ def __init__(
base_url=base_url,
# cast to a valid type because mypy doesn't understand our type narrowing
timeout=cast(Timeout, timeout),
proxies=proxies,
transport=transport,
limits=limits,
follow_redirects=True,
**kwargs, # type: ignore
)

def is_closed(self) -> bool:
Expand Down
8 changes: 3 additions & 5 deletions src/anthropic/_compat.py
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,8 @@ def model_dump(
exclude=exclude,
exclude_unset=exclude_unset,
exclude_defaults=exclude_defaults,
warnings=warnings,
# warnings are not supported in Pydantic v1
warnings=warnings if PYDANTIC_V2 else True,
)
return cast(
"dict[str, Any]",
Expand Down Expand Up @@ -213,9 +214,6 @@ def __set_name__(self, owner: type[Any], name: str) -> None: ...
# __set__ is not defined at runtime, but @cached_property is designed to be settable
def __set__(self, instance: object, value: _T) -> None: ...
else:
try:
from functools import cached_property as cached_property
except ImportError:
from cached_property import cached_property as cached_property
from functools import cached_property as cached_property

typed_cached_property = cached_property
7 changes: 5 additions & 2 deletions src/anthropic/_legacy_response.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@

from ._types import NoneType
from ._utils import is_given, extract_type_arg, is_annotated_type
from ._models import BaseModel, is_basemodel
from ._models import BaseModel, is_basemodel, add_request_id
from ._constants import RAW_RESPONSE_HEADER
from ._streaming import Stream, AsyncStream, is_stream_class_type, extract_stream_chunk_type
from ._exceptions import APIResponseValidationError
Expand Down Expand Up @@ -140,8 +140,11 @@ class MyModel(BaseModel):
if is_given(self._options.post_parser):
parsed = self._options.post_parser(parsed)

if isinstance(parsed, BaseModel):
add_request_id(parsed, self.request_id)

self._parsed_by_type[cache_key] = parsed
return parsed
return cast(R, parsed)

@property
def headers(self) -> httpx.Headers:
Expand Down
33 changes: 32 additions & 1 deletion src/anthropic/_models.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

import os
import inspect
from typing import TYPE_CHECKING, Any, Type, Union, Generic, TypeVar, Callable, cast
from typing import TYPE_CHECKING, Any, Type, Union, Generic, TypeVar, Callable, Optional, cast
from datetime import date, datetime
from typing_extensions import (
Unpack,
Expand Down Expand Up @@ -95,6 +95,22 @@ def model_fields_set(self) -> set[str]:
class Config(pydantic.BaseConfig): # pyright: ignore[reportDeprecated]
extra: Any = pydantic.Extra.allow # type: ignore

if TYPE_CHECKING:
_request_id: Optional[str] = None
"""The ID of the request, returned via the `request-id` header. Useful for debugging requests and reporting issues to Anthropic.
This will **only** be set for the top-level response object, it will not be defined for nested objects. For example:

```py
message = await client.messages.create(...)
message._request_id # req_xxx
message.usage._request_id # raises `AttributeError`
```

Note: unlike other properties that use an `_` prefix, this property
*is* public. Unless documented otherwise, all other `_` prefix properties,
methods and modules are *private*.
"""

def to_dict(
self,
*,
Expand Down Expand Up @@ -665,6 +681,21 @@ def set_pydantic_config(typ: Any, config: pydantic.ConfigDict) -> None:
setattr(typ, "__pydantic_config__", config) # noqa: B010


def add_request_id(obj: BaseModel, request_id: str | None) -> None:
obj._request_id = request_id

# in Pydantic v1, using setattr like we do above causes the attribute
# to be included when serializing the model which we don't want in this
# case so we need to explicitly exclude it
if not PYDANTIC_V2:
try:
exclude_fields = obj.__exclude_fields__ # type: ignore
except AttributeError:
cast(Any, obj).__exclude_fields__ = {"_request_id", "__exclude_fields__"}
else:
cast(Any, obj).__exclude_fields__ = {*(exclude_fields or {}), "_request_id", "__exclude_fields__"}


# our use of subclasssing here causes weirdness for type checkers,
# so we just pretend that we don't subclass
if TYPE_CHECKING:
Expand Down
Loading