This is an automated email from the ASF dual-hosted git repository.

amoghrajesh pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/airflow.git


The following commit(s) were added to refs/heads/main by this push:
     new 5677af31e96 Migrate anthropic provider to use anthropic 1.x SDK 
(#72094)
5677af31e96 is described below

commit 5677af31e96a40c088ffdb454d2f7842cd47a921
Author: Amogh Desai <[email protected]>
AuthorDate: Tue Sep 8 03:17:31 2026 -0500

    Migrate anthropic provider to use anthropic 1.x SDK (#72094)
---
 providers/anthropic/README.rst                     | 20 +++++------
 providers/anthropic/docs/connections.rst           |  3 +-
 providers/anthropic/docs/index.rst                 | 20 +++++------
 providers/anthropic/pyproject.toml                 | 17 +++------
 .../airflow/providers/anthropic/hooks/anthropic.py | 28 ++++++++++++---
 .../tests/unit/anthropic/hooks/test_anthropic.py   | 41 +++++++++++++++++++---
 uv.lock                                            | 17 +++++----
 7 files changed, 95 insertions(+), 51 deletions(-)

diff --git a/providers/anthropic/README.rst b/providers/anthropic/README.rst
index aa2a8a925e3..eefc65dc614 100644
--- a/providers/anthropic/README.rst
+++ b/providers/anthropic/README.rst
@@ -52,24 +52,24 @@ The package supports the following python versions: 
3.10,3.11,3.12,3.13,3.14
 Requirements
 ------------
 
-==========================================  ====================
+==========================================  ==================
 PIP package                                 Version required
-==========================================  ====================
+==========================================  ==================
 ``apache-airflow``                          ``>=3.0.0``
 ``apache-airflow-providers-common-compat``  ``>=1.12.0``
-``anthropic``                               ``>=0.121.0,<1.0.0``
-==========================================  ====================
+``anthropic``                               ``>=1.0.0``
+==========================================  ==================
 
 Optional dependencies
 ----------------------
 
-===========  ===============================
+===========  =============================
 Extra        Dependencies
-===========  ===============================
-``bedrock``  ``anthropic[bedrock]>=0.121.0``
-``vertex``   ``anthropic[vertex]>=0.121.0``
-``aws``      ``anthropic[aws]>=0.121.0``
-===========  ===============================
+===========  =============================
+``bedrock``  ``anthropic[bedrock]>=1.0.0``
+``vertex``   ``anthropic[vertex]>=1.0.0``
+``aws``      ``anthropic[aws]>=1.0.0``
+===========  =============================
 
 The changelog for the provider package can be found in the
 `changelog 
<https://airflow.apache.org/docs/apache-airflow-providers-anthropic/0.3.0/changelog.html>`_.
diff --git a/providers/anthropic/docs/connections.rst 
b/providers/anthropic/docs/connections.rst
index 55725e29ccf..71c87a0d912 100644
--- a/providers/anthropic/docs/connections.rst
+++ b/providers/anthropic/docs/connections.rst
@@ -49,7 +49,8 @@ Extra (optional)
       ``model`` (e.g. ``hook.create_message(...)``, 
``hook.create_agent(...)``). Set it here
       to change the model without editing Dags; falls back to the provider 
default
       (``claude-opus-4-8``).
-    * ``aws_region`` — AWS region for the ``bedrock`` and ``aws`` platforms.
+    * ``aws_region`` — AWS region for the ``bedrock`` and ``aws`` platforms. 
Required unless the
+      worker resolves a region from ``AWS_REGION`` / ``AWS_DEFAULT_REGION`` or 
its AWS profile.
     * ``project_id`` / ``region`` — GCP project and region for the ``vertex`` 
platform.
     * ``resource`` — Azure resource name for the ``foundry`` platform.
     * ``anthropic_client_kwargs`` — a nested dictionary forwarded verbatim to 
the client
diff --git a/providers/anthropic/docs/index.rst 
b/providers/anthropic/docs/index.rst
index fd9c4ef97f7..f8c1b8a2db2 100644
--- a/providers/anthropic/docs/index.rst
+++ b/providers/anthropic/docs/index.rst
@@ -133,13 +133,13 @@ Requirements
 
 The minimum Apache Airflow version supported by this provider distribution is 
``3.0.0``.
 
-==========================================  ====================
+==========================================  ==================
 PIP package                                 Version required
-==========================================  ====================
+==========================================  ==================
 ``apache-airflow``                          ``>=3.0.0``
 ``apache-airflow-providers-common-compat``  ``>=1.12.0``
-``anthropic``                               ``>=0.121.0,<1.0.0``
-==========================================  ====================
+``anthropic``                               ``>=1.0.0``
+==========================================  ==================
 
 Optional dependencies
 ---------------------
@@ -152,13 +152,13 @@ Install them when installing from PyPI. For example:
     pip install apache-airflow-providers-anthropic[bedrock]
 
 
-===========  ======================================
+===========  =============================
 Extra        Dependencies
-===========  ======================================
-``bedrock``  ``anthropic[bedrock]>=0.121.0,<1.0.0``
-``vertex``   ``anthropic[vertex]>=0.121.0,<1.0.0``
-``aws``      ``anthropic[aws]>=0.121.0,<1.0.0``
-===========  ======================================
+===========  =============================
+``bedrock``  ``anthropic[bedrock]>=1.0.0``
+``vertex``   ``anthropic[vertex]>=1.0.0``
+``aws``      ``anthropic[aws]>=1.0.0``
+===========  =============================
 
 Downloading official packages
 -----------------------------
diff --git a/providers/anthropic/pyproject.toml 
b/providers/anthropic/pyproject.toml
index a967811f13f..ba030a4dcf9 100644
--- a/providers/anthropic/pyproject.toml
+++ b/providers/anthropic/pyproject.toml
@@ -61,24 +61,15 @@ requires-python = ">=3.10"
 dependencies = [
     "apache-airflow>=3.0.0",
     "apache-airflow-providers-common-compat>=1.12.0",
-    # 0.121.0 is the first release whose ``sessions.create`` accepts 
``budget``, which is
-    # how the guide tells users to set a session ceiling. Reading a 
``budget_reached`` stop
-    # reason happens to work further back -- older clients mis-build the 
discriminated
-    # union into the wrong variant class while preserving ``.type`` -- but 
only with
-    # response validation left non-strict, so it is not something to depend on.
-    # anthropic 1.0.0 replaces httpx with httpx2 and is a major release the 
provider
-    # has not been validated against. Remove the <1.0.0 cap (here and in the 
extras
-    # below) after migrating to the 1.x SDK;
-    # tracked at https://github.com/apache/airflow/issues/72071
-    "anthropic>=0.121.0,<1.0.0",
+    "anthropic>=1.0.0",
 ]
 
 # The optional dependencies should be modified in place in the generated file
 # Any change in the dependencies is preserved when the file is regenerated
 [project.optional-dependencies]
-"bedrock" = ["anthropic[bedrock]>=0.121.0,<1.0.0"]
-"vertex" = ["anthropic[vertex]>=0.121.0,<1.0.0"]
-"aws" = ["anthropic[aws]>=0.121.0,<1.0.0"]
+"bedrock" = ["anthropic[bedrock]>=1.0.0"]
+"vertex" = ["anthropic[vertex]>=1.0.0"]
+"aws" = ["anthropic[aws]>=1.0.0"]
 
 [dependency-groups]
 dev = [
diff --git 
a/providers/anthropic/src/airflow/providers/anthropic/hooks/anthropic.py 
b/providers/anthropic/src/airflow/providers/anthropic/hooks/anthropic.py
index 864a6bbb813..023729f2636 100644
--- a/providers/anthropic/src/airflow/providers/anthropic/hooks/anthropic.py
+++ b/providers/anthropic/src/airflow/providers/anthropic/hooks/anthropic.py
@@ -50,7 +50,7 @@ from airflow.providers.common.compat.sdk import 
AirflowSkipException, BaseHook
 logger = logging.getLogger(__name__)
 
 if TYPE_CHECKING:
-    from collections.abc import Iterable, Iterator
+    from collections.abc import Callable, Iterable, Iterator
 
     from anthropic.types import Message
     from anthropic.types.beta import (
@@ -295,7 +295,8 @@ class AnthropicHook(BaseHook):
     - ``platform``: one of ``anthropic`` (default), ``bedrock``, ``vertex``, 
``aws``, ``foundry``.
     - ``model``: default model id used when an operator/hook call omits 
``model`` (lets you
       change the model without editing Dags); falls back to 
:data:`DEFAULT_MODEL`.
-    - ``aws_region``: region for the ``bedrock`` and ``aws`` platforms.
+    - ``aws_region``: region for the ``bedrock`` and ``aws`` platforms. 
Required unless the
+      worker resolves one from ``AWS_REGION`` / ``AWS_DEFAULT_REGION`` or its 
AWS profile.
     - ``project_id`` / ``region``: project and region for the ``vertex`` 
platform.
     - ``resource``: Azure resource name for the ``foundry`` platform.
     - ``anthropic_client_kwargs``: extra keyword arguments forwarded to the 
client
@@ -342,6 +343,25 @@ class AnthropicHook(BaseHook):
         """Return the Anthropic client for the configured platform."""
         return self.get_conn()
 
+    def _build_aws_client(
+        self,
+        factory: Callable[..., AnthropicClient],
+        aws_region: str | None,
+        client_kwargs: dict[str, Any],
+    ) -> AnthropicClient:
+        try:
+            return factory(aws_region=aws_region, **client_kwargs)
+        except ValueError as exc:
+            # anthropic 1.x dropped the implicit us-east-1 fallback, so an 
unset region now
+            # fails at client construction. Point at the connection rather 
than the SDK.
+            if aws_region:
+                raise
+            raise AnthropicError(
+                f"No AWS region configured for the {self.platform!r} platform. 
Set 'aws_region' in the "
+                f"extra of connection {self.conn_id!r}, or set AWS_REGION / 
AWS_DEFAULT_REGION (or a "
+                "region on the AWS profile) on the worker."
+            ) from exc
+
     def get_conn(self) -> AnthropicClient:
         """Build and return the Anthropic client for the configured 
platform."""
         conn = self._connection
@@ -350,13 +370,13 @@ class AnthropicHook(BaseHook):
         platform = self.platform
         self.log.debug("Building Anthropic client for platform %r 
(conn_id=%s)", platform, self.conn_id)
         if platform == "bedrock":
-            return AnthropicBedrock(aws_region=extras.get("aws_region"), 
**client_kwargs)
+            return self._build_aws_client(AnthropicBedrock, 
extras.get("aws_region"), client_kwargs)
         if platform == "vertex":
             return AnthropicVertex(
                 project_id=extras.get("project_id"), 
region=extras.get("region"), **client_kwargs
             )
         if platform == "aws":
-            return AnthropicAWS(aws_region=extras.get("aws_region"), 
**client_kwargs)
+            return self._build_aws_client(AnthropicAWS, 
extras.get("aws_region"), client_kwargs)
         if platform == "foundry":
             api_key = client_kwargs.pop("api_key", None) or conn.password
             return AnthropicFoundry(api_key=api_key, 
resource=extras.get("resource"), **client_kwargs)
diff --git a/providers/anthropic/tests/unit/anthropic/hooks/test_anthropic.py 
b/providers/anthropic/tests/unit/anthropic/hooks/test_anthropic.py
index 816b238d401..3ba0842d7e6 100644
--- a/providers/anthropic/tests/unit/anthropic/hooks/test_anthropic.py
+++ b/providers/anthropic/tests/unit/anthropic/hooks/test_anthropic.py
@@ -45,7 +45,6 @@ from airflow.providers.anthropic.hooks.anthropic import (
 
 pytest.importorskip("anthropic")
 
-import httpx
 from anthropic import BadRequestError
 from anthropic.types import BetaMonetaryAmount
 from anthropic.types.beta import BetaManagedAgentsServerToolUsage, 
BetaManagedAgentsSessionUsage
@@ -281,10 +280,17 @@ class TestBuildBudget:
             build_budget(amount)
 
 
+class _StubResponse:
+    """The only response attributes ``APIStatusError`` reads, so no HTTP 
library is needed."""
+
+    status_code = 400
+    headers: dict[str, str] = {}
+    request = None
+
+
 def _make_bad_request(message="cannot be archived while its status is 
running") -> BadRequestError:
     """A real SDK BadRequestError -- archive_session only interrupts on this, 
not on any error."""
-    request = httpx.Request("POST", 
"https://api.anthropic.com/v1/sessions/sess_1/archive";)
-    return BadRequestError(message, response=httpx.Response(400, 
request=request), body=None)
+    return BadRequestError(message, response=_StubResponse(), body=None)  # 
type: ignore[arg-type]
 
 
 class TestArchiveSession:
@@ -679,11 +685,38 @@ class TestAnthropicHookGetConn:
     @mock.patch(f"{HOOK_PATH}.AnthropicAWS", autospec=True)
     @mock.patch.object(AnthropicHook, "get_connection")
     def test_aws_platform_without_region(self, mock_get_connection, mock_aws):
-        # No aws_region configured -> pass None so the SDK falls back to its 
own resolution.
+        # No aws_region configured -> pass None so the SDK can still resolve 
one from the
+        # environment or the AWS profile; it only fails when nothing supplies 
a region.
         mock_get_connection.return_value = _conn(extra={"platform": "aws"})
         AnthropicHook().get_conn()
         mock_aws.assert_called_once_with(aws_region=None)
 
+    @pytest.mark.parametrize(
+        ("platform", "client_name"),
+        [("bedrock", "AnthropicBedrock"), ("aws", "AnthropicAWS")],
+    )
+    @mock.patch.object(AnthropicHook, "get_connection")
+    def test_unresolvable_aws_region_points_at_the_connection(
+        self, mock_get_connection, platform, client_name
+    ):
+        mock_get_connection.return_value = _conn(extra={"platform": platform})
+        sdk_error = ValueError("No AWS region was provided.")
+        with mock.patch(f"{HOOK_PATH}.{client_name}", side_effect=sdk_error):
+            with pytest.raises(AnthropicError) as exc_info:
+                AnthropicHook().get_conn()
+        message = str(exc_info.value)
+        assert f"No AWS region configured for the {platform!r} platform" in 
message
+        assert "'aws_region'" in message
+        assert "'anthropic_default'" in message
+        assert exc_info.value.__cause__ is sdk_error
+
+    @mock.patch.object(AnthropicHook, "get_connection")
+    def test_sdk_value_error_is_not_masked_when_a_region_is_configured(self, 
mock_get_connection):
+        mock_get_connection.return_value = _conn(extra={"platform": "bedrock", 
"aws_region": "us-east-1"})
+        with mock.patch(f"{HOOK_PATH}.AnthropicBedrock", 
side_effect=ValueError("bad profile")):
+            with pytest.raises(ValueError, match="bad profile"):
+                AnthropicHook().get_conn()
+
     @mock.patch(f"{HOOK_PATH}.AnthropicFoundry")
     @mock.patch.object(AnthropicHook, "get_connection")
     def test_foundry_platform(self, mock_get_connection, mock_foundry):
diff --git a/uv.lock b/uv.lock
index 7e52ab5f4e4..fb803c564a5 100644
--- a/uv.lock
+++ b/uv.lock
@@ -1097,21 +1097,20 @@ wheels = [
 
 [[package]]
 name = "anthropic"
-version = "0.125.0"
+version = "1.0.0"
 source = { registry = "https://pypi.org/simple"; }
 dependencies = [
     { name = "anyio" },
-    { name = "distro" },
     { name = "docstring-parser" },
-    { name = "httpx" },
+    { name = "httpx2" },
     { name = "jiter" },
     { name = "pydantic" },
     { name = "sniffio" },
     { name = "typing-extensions" },
 ]
-sdist = { url = 
"https://files.pythonhosted.org/packages/62/f8/6f0560884b5363848347bd640b6c1d04abc25e7aa61787a232f790c6b60a/anthropic-0.125.0.tar.gz";,
 hash = 
"sha256:e0cdd336580cb7411c1cdab69f80973e9bf4bff7f8e08141811d46307d45c682", size 
= 1112593, upload-time = "2026-08-19T22:00:42.837Z" }
+sdist = { url = 
"https://files.pythonhosted.org/packages/25/aa/4978e58035bd6c638c7b483450a68b7ef2d732ab78885e27bb9db0cff1a2/anthropic-1.0.0.tar.gz";,
 hash = 
"sha256:42be3c97604af7252c5898413aee076ace6c46e9bca0d0d90ceb77c7d3719027", size 
= 1077769, upload-time = "2026-08-20T19:59:00.565Z" }
 wheels = [
-    { url = 
"https://files.pythonhosted.org/packages/2f/1a/b1bd30cda3790557e8791bec5922a6ec8fabb6fa8b008c76a39cf7be6152/anthropic-0.125.0-py3-none-any.whl";,
 hash = 
"sha256:3486013602eca76d8b12540764e53654f02cf4951110bca86cf06e67428a9f21", size 
= 1184067, upload-time = "2026-08-19T22:00:44.596Z" },
+    { url = 
"https://files.pythonhosted.org/packages/ad/5b/db4a854aebf5d33a5ab714c46af6eb85ee44f390ed29b7b325c00b9f11ed/anthropic-1.0.0-py3-none-any.whl";,
 hash = 
"sha256:32dd52e9e1d774393b27182f451398ba4262287a4d0eab30887f89f1481b3ae4", size 
= 1171725, upload-time = "2026-08-20T19:58:58.725Z" },
 ]
 
 [package.optional-dependencies]
@@ -3442,10 +3441,10 @@ docs = [
 
 [package.metadata]
 requires-dist = [
-    { name = "anthropic", specifier = ">=0.121.0,<1.0.0" },
-    { name = "anthropic", extras = ["aws"], marker = "extra == 'aws'", 
specifier = ">=0.121.0,<1.0.0" },
-    { name = "anthropic", extras = ["bedrock"], marker = "extra == 'bedrock'", 
specifier = ">=0.121.0,<1.0.0" },
-    { name = "anthropic", extras = ["vertex"], marker = "extra == 'vertex'", 
specifier = ">=0.121.0,<1.0.0" },
+    { name = "anthropic", specifier = ">=1.0.0" },
+    { name = "anthropic", extras = ["aws"], marker = "extra == 'aws'", 
specifier = ">=1.0.0" },
+    { name = "anthropic", extras = ["bedrock"], marker = "extra == 'bedrock'", 
specifier = ">=1.0.0" },
+    { name = "anthropic", extras = ["vertex"], marker = "extra == 'vertex'", 
specifier = ">=1.0.0" },
     { name = "apache-airflow", editable = "." },
     { name = "apache-airflow-providers-common-compat", editable = 
"providers/common/compat" },
 ]

Reply via email to