Five Changes, and One Order to Apply Them In
A routine pip install -U anthropic now crosses a major boundary. Pin deliberately instead, so a later 2.0 does not repeat this by accident:
pip install --upgrade "anthropic>=1,<2"
Then work through the breaking changes in dependency order rather than in the order you happen to hit them. Each row below blocks the ones under it, and each fails in a different part of the repository:
| # | Change | Where it fails first |
|---|---|---|
| 1 | Minimum Python rises from 3.9 to 3.10 | Base image, requires-python, CI matrix |
| 2 | httpx replaced by httpx2 | Tracing, mocking, test fixtures, custom transports |
| 3 | temperature, top_p, top_k removed | Request construction and config plumbing |
| 4 | Async raw responses must be awaited | Any async code reading headers or request IDs |
| 5 | AnthropicBedrock requires a region | Client construction, at import or startup |
Step one is not optional and not negotiable, so do it alone and merge it alone. If any service still runs Python 3.9, the SDK upgrade is blocked behind an interpreter upgrade with its own risk profile, and mixing the two makes a bisect useless. The general method for staging a dependency bump like this — inventory, pin, stage, verify — is covered in the AI dependency upgrade plan; this brief stays with what 1.0 specifically breaks.
httpx2 Is the Change That Breaks Your Test Suite
The SDK now sends requests with httpx2, an API-compatible fork of httpx maintained by the Pydantic team, on the stated grounds that httpx is no longer actively maintained. Because the fork is API-compatible, application code that passes only plain values to client.messages.create() may need no HTTP-layer edit. The breakage is in everything you wrapped around the client.
Anything that constructs an HTTP object by hand has to import from the new package. Timeouts still accept a plain float, or an httpx2.Timeout for granular control:
# Before
import httpx
from anthropic import Anthropic, DefaultHttpxClient
client = Anthropic(
timeout=httpx.Timeout(60.0, connect=5.0),
http_client=DefaultHttpxClient(transport=httpx.HTTPTransport(local_address="0.0.0.0")),
)
# After
import httpx2
from anthropic import Anthropic, DefaultHttpxClient
client = Anthropic(
timeout=httpx2.Timeout(60.0, connect=5.0),
http_client=DefaultHttpxClient(transport=httpx2.HTTPTransport(local_address="0.0.0.0")),
)
This one fails loudly, which is the good case: passing a client from the old httpx package as http_client raises a TypeError. Keep using DefaultHttpxClient and DefaultAsyncHttpxClient rather than a bare httpx2.Client, so the SDK's own defaults for timeouts and connection limits survive your customisation.
Tools that work by patching the httpx package no longer see the SDK's traffic, because the SDK no longer uses that package. The documented list includes OpenTelemetry's HTTPXClientInstrumentor, Sentry's httpx integration, respx, pytest-httpx, and vcrpy. Nothing raises. Spans stop appearing, and a mocked test either falls through to a real network call or fails on an assertion that has nothing to do with the change. Call httpx2.alias_httpx() once at startup, before anything imports httpx: it makes import httpx resolve to httpx2 for the whole process.
“Before anything imports httpx” is a real constraint, not a stylistic preference, and it is why a conftest fixture is often too late. For pytest, the guide's own recipe is to put the call in a plugin module and load it as a plugin:
import httpx2
httpx2.alias_httpx()
[tool.pytest.ini_options]
addopts = "-p tests._alias_httpx"
Decide per environment whether you want the alias or the explicit httpx2 import. The alias is the right answer when a third-party library you do not control patches httpx. Editing the imports is the right answer in your own code, because it keeps the dependency visible. Using the alias to avoid touching your own imports works, and hides the migration from the next reader. Verify the outcome rather than the diff: run one instrumented request and confirm the span or the recorded cassette actually appears. This is exactly the class of change where the test layer is the thing under test, which is the operating idea behind the testing with AI guide.
Removed Parameters, and the Escape Hatch
The sampling parameters are gone from messages.create(), messages.stream(), messages.parse(), and the related helpers. This follows the API itself: current Claude models do not use temperature, top_p, or top_k, so for most callers the correct migration is deletion, not translation. If you are pinned to an older model that still accepts a sampling setting, the guide's documented path is extra_body, which is merged into the request JSON as-is:
# Before
client.messages.create(..., model="claude-sonnet-4-6", temperature=0.2)
# After
client.messages.create(..., model="claude-sonnet-4-6", extra_body={"temperature": 0.2})
Treat that as a deliberate, temporary decision with the model pin written next to it. extra_body bypasses the SDK's typing by design, so it will not warn you when the parameter later stops being valid for the model you moved to. If the original intent was determinism or variety rather than a specific number, write that intent down as a behaviour requirement and test it explicitly instead of treating extra_body as a permanent replacement — the Claude API guide covers the controls available on current models.
The same release removes the legacy Text Completions API: client.completions.create(), its Completion types, and the HUMAN_PROMPT and AI_PROMPT constants. That is a rewrite onto client.messages.create(), not a rename, and it is the one item on this list that deserves its own change and its own review. Three smaller removals travel with it: output_format={...} becomes output_config={"format": {...}}, messages.parse(stream=True) is replaced by the streaming helper, and the tool runner's client-side compaction_control gives way to server-side context_management.
Two Changes That Only Bite at Runtime
On the async client, reading a raw response is now asynchronous. parse(), read(), text(), and json() are coroutines on AsyncAPIResponse, and on both clients .text and .content became methods rather than properties:
# Before
response = await client.messages.with_raw_response.create(...)
message = response.parse()
# After
response = await client.messages.with_raw_response.create(...)
message = await response.parse()
A missing await does not raise where the mistake is. It yields a coroutine object that fails later, in whatever code expected a Message. The same applies to .with_streaming_response. Grep for with_raw_response and with_streaming_response and read every async call site; these usually live in logging and request-ID plumbing, which is code that runs on the error path and is rarely covered by a happy-path test.
Finally, AnthropicBedrock() no longer falls back to us-east-1 when nothing is configured. It raises a ValueError at construction time, so a deployment that quietly relied on the implicit default now fails at startup. Pass aws_region= or set AWS_REGION. The failure is loud, and it will find any environment where the region was never actually set — which is the point.
What the Tooling Promises, and What You Must Verify
Claude Code 2.1.239, released August 21, 2026, added a /claude-api upgrade command for migrating Python projects from anthropic 0.x to 1.x. The migration guide recommends it as the fastest route: run /claude-api upgrade python in the project and review the diff. Pair it with a type checker, which the guide describes as a good checklist even if you do not normally run one — pyright or mypy will flag almost every breaking change as an error after the upgrade.
The published documentation does not give a per-edit coverage contract for the command. It says that the command migrates 0.x Python projects, then tells you to review the diff; do not infer that an unchanged file was inspected or that a changed line is correct. Verify every item in the migration guide after it runs. The human decisions are clearest where the guide offers two valid answers: deleting a sampling parameter or preserving it through extra_body depends on the model at that call site, and aliasing httpx or rewriting imports depends on which libraries patch it. Replacing a Text Completions call also means deciding what the prompt should become. Treat the command as an editor, not as evidence that the migration is complete.
The operating decision
Ship the Python 3.10 floor as its own change. Then upgrade the SDK pinned to >=1,<2, run /claude-api upgrade python, and use pyright or mypy as the checklist. Prove the httpx2 move against your instrumentation and mocks specifically — a passing test suite is only evidence once you have confirmed the mocks are still intercepting anything.
Sources checked August 22, 2026
- Anthropic: Migrating to Anthropic SDK v1 (Python)
- Anthropic: anthropic-sdk-python releases, v1.0.0 published August 20, 2026
- Anthropic: Claude Platform release notes, August 20, 2026
- Anthropic: Python SDK reference (requirements, timeouts, HTTP client, raw responses)
- Anthropic: Claude Code changelog, v2.1.239 adds
/claude-api upgrade