You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@airflow.apache.org by vi...@apache.org on 2026/05/04 13:49:06 UTC

(airflow) branch main updated: Add `S3TablesDeleteTableBucketOperator` (#66120)

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

vincbeck 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 29c4565a7e7 Add `S3TablesDeleteTableBucketOperator` (#66120)
29c4565a7e7 is described below

commit 29c4565a7e7aeb6b597270bd2ade2ad422280e43
Author: John Jackson <75...@users.noreply.github.com>
AuthorDate: Mon May 4 06:48:58 2026 -0700

    Add `S3TablesDeleteTableBucketOperator` (#66120)
---
 providers/amazon/docs/operators/s3_tables.rst      | 14 +++++++++++
 .../providers/amazon/aws/operators/s3_tables.py    | 29 ++++++++++++++++++++++
 .../tests/system/amazon/aws/example_s3_tables.py   | 26 ++++++++-----------
 .../unit/amazon/aws/operators/test_s3_tables.py    | 27 +++++++++++++++++---
 4 files changed, 77 insertions(+), 19 deletions(-)

diff --git a/providers/amazon/docs/operators/s3_tables.rst b/providers/amazon/docs/operators/s3_tables.rst
index ee4bc5e847d..bf625e54dff 100644
--- a/providers/amazon/docs/operators/s3_tables.rst
+++ b/providers/amazon/docs/operators/s3_tables.rst
@@ -61,6 +61,20 @@ To delete a table from an Amazon S3 Tables namespace, use
     :start-after: [START howto_operator_s3tables_delete_table]
     :end-before: [END howto_operator_s3tables_delete_table]
 
+.. _howto/operator:S3TablesDeleteTableBucketOperator:
+
+Delete a Table Bucket
+---------------------
+
+To delete an Amazon S3 Tables table bucket, use
+:class:`~airflow.providers.amazon.aws.operators.s3_tables.S3TablesDeleteTableBucketOperator`.
+
+.. exampleinclude:: /../../amazon/tests/system/amazon/aws/example_s3_tables.py
+    :language: python
+    :dedent: 4
+    :start-after: [START howto_operator_s3tables_delete_table_bucket]
+    :end-before: [END howto_operator_s3tables_delete_table_bucket]
+
 Reference
 ---------
 
diff --git a/providers/amazon/src/airflow/providers/amazon/aws/operators/s3_tables.py b/providers/amazon/src/airflow/providers/amazon/aws/operators/s3_tables.py
index b38ef9f7a09..faed3e2ecea 100644
--- a/providers/amazon/src/airflow/providers/amazon/aws/operators/s3_tables.py
+++ b/providers/amazon/src/airflow/providers/amazon/aws/operators/s3_tables.py
@@ -223,3 +223,32 @@ class S3TablesCreateTableBucketOperator(AwsBaseOperator[S3TablesHook]):
                 raise
         self.log.info("Table bucket %s: %s", self.table_bucket_name, bucket_arn)
         return bucket_arn
+
+
+class S3TablesDeleteTableBucketOperator(AwsBaseOperator[S3TablesHook]):
+    """
+    Delete an Amazon S3 Tables table bucket.
+
+    .. seealso::
+        For more information on how to use this operator, take a look at the guide:
+        :ref:`howto/operator:S3TablesDeleteTableBucketOperator`
+
+    :param table_bucket_arn: The ARN of the table bucket to delete. (templated)
+    """
+
+    template_fields: Sequence[str] = aws_template_fields("table_bucket_arn")
+    aws_hook_class = S3TablesHook
+
+    def __init__(
+        self,
+        *,
+        table_bucket_arn: str,
+        **kwargs,
+    ) -> None:
+        super().__init__(**kwargs)
+        self.table_bucket_arn = table_bucket_arn
+
+    def execute(self, context: Context) -> None:
+        self.log.info("Deleting S3 Tables table bucket %s", self.table_bucket_arn)
+        self.hook.conn.delete_table_bucket(tableBucketARN=self.table_bucket_arn)
+        self.log.info("Deleted table bucket %s", self.table_bucket_arn)
diff --git a/providers/amazon/tests/system/amazon/aws/example_s3_tables.py b/providers/amazon/tests/system/amazon/aws/example_s3_tables.py
index 102de5f4b76..52492cc3542 100644
--- a/providers/amazon/tests/system/amazon/aws/example_s3_tables.py
+++ b/providers/amazon/tests/system/amazon/aws/example_s3_tables.py
@@ -21,6 +21,7 @@ from datetime import datetime
 from airflow.providers.amazon.aws.operators.s3_tables import (
     S3TablesCreateTableBucketOperator,
     S3TablesCreateTableOperator,
+    S3TablesDeleteTableBucketOperator,
     S3TablesDeleteTableOperator,
 )
 from airflow.providers.common.compat.sdk import DAG, chain
@@ -33,8 +34,6 @@ else:
     from airflow.decorators import task  # type: ignore[attr-defined,no-redef]
     from airflow.utils.trigger_rule import TriggerRule  # type: ignore[no-redef,attr-defined]
 
-import contextlib
-
 from system.amazon.aws.utils import ENV_ID_KEY, SystemTestContextBuilder
 
 DAG_ID = "example_s3_tables"
@@ -77,18 +76,7 @@ with DAG(
         """Delete the namespace."""
         import boto3
 
-        client = boto3.client("s3tables")
-        with contextlib.suppress(client.exceptions.NotFoundException):
-            client.delete_namespace(tableBucketARN=table_bucket_arn, namespace=namespace)
-
-    @task(trigger_rule=TriggerRule.ALL_DONE)
-    def delete_table_bucket(table_bucket_arn: str):
-        """Delete the table bucket."""
-        import boto3
-
-        client = boto3.client("s3tables")
-        with contextlib.suppress(client.exceptions.NotFoundException):
-            client.delete_table_bucket(tableBucketARN=table_bucket_arn)
+        boto3.client("s3tables").delete_namespace(tableBucketARN=table_bucket_arn, namespace=namespace)
 
     # [START howto_operator_s3tables_create_table_bucket]
     create_table_bucket = S3TablesCreateTableBucketOperator(
@@ -118,6 +106,14 @@ with DAG(
     )
     # [END howto_operator_s3tables_delete_table]
 
+    # [START howto_operator_s3tables_delete_table_bucket]
+    delete_table_bucket = S3TablesDeleteTableBucketOperator(
+        task_id="delete_table_bucket",
+        table_bucket_arn=create_table_bucket.output,
+        trigger_rule=TriggerRule.ALL_DONE,
+    )
+    # [END howto_operator_s3tables_delete_table_bucket]
+
     chain(
         # TEST SETUP
         test_context,
@@ -128,7 +124,7 @@ with DAG(
         # TEST TEARDOWN
         delete_table,
         delete_namespace(table_bucket_arn=create_table_bucket.output, namespace=namespace),
-        delete_table_bucket(table_bucket_arn=create_table_bucket.output),
+        delete_table_bucket,
     )
 
     from tests_common.test_utils.watcher import watcher
diff --git a/providers/amazon/tests/unit/amazon/aws/operators/test_s3_tables.py b/providers/amazon/tests/unit/amazon/aws/operators/test_s3_tables.py
index 6aa45edf4b2..541c21cd5b8 100644
--- a/providers/amazon/tests/unit/amazon/aws/operators/test_s3_tables.py
+++ b/providers/amazon/tests/unit/amazon/aws/operators/test_s3_tables.py
@@ -27,6 +27,7 @@ from airflow.providers.amazon.aws.hooks.s3_tables import S3TablesHook
 from airflow.providers.amazon.aws.operators.s3_tables import (
     S3TablesCreateTableBucketOperator,
     S3TablesCreateTableOperator,
+    S3TablesDeleteTableBucketOperator,
     S3TablesDeleteTableOperator,
 )
 
@@ -36,6 +37,8 @@ TABLE_BUCKET_ARN = "arn:aws:s3tables:us-east-1:123456789012:bucket/test-bucket"
 NAMESPACE = "test_namespace"
 TABLE_NAME = "test_table"
 TABLE_ARN = "arn:aws:s3tables:us-east-1:123456789012:bucket/test-bucket/table/test-id"
+BUCKET_NAME = "test-table-bucket"
+BUCKET_ARN = "arn:aws:s3tables:us-east-1:123456789012:bucket/test-table-bucket"
 
 
 class TestS3TablesCreateTableOperator:
@@ -134,10 +137,6 @@ class TestS3TablesDeleteTableOperator:
         validate_template_fields(self.operator)
 
 
-BUCKET_NAME = "test-table-bucket"
-BUCKET_ARN = "arn:aws:s3tables:us-east-1:123456789012:bucket/test-table-bucket"
-
-
 class TestS3TablesCreateTableBucketOperator:
     def setup_method(self):
         self.operator = S3TablesCreateTableBucketOperator(
@@ -212,3 +211,23 @@ class TestS3TablesCreateTableBucketOperator:
 
     def test_template_fields(self):
         validate_template_fields(self.operator)
+
+
+class TestS3TablesDeleteTableBucketOperator:
+    def setup_method(self):
+        self.operator = S3TablesDeleteTableBucketOperator(
+            task_id="delete_table_bucket",
+            table_bucket_arn=BUCKET_ARN,
+        )
+
+    @mock.patch.object(S3TablesHook, "conn", new_callable=mock.PropertyMock)
+    def test_execute(self, mock_conn):
+        mock_client = mock.MagicMock()
+        mock_conn.return_value = mock_client
+
+        self.operator.execute({})
+
+        mock_client.delete_table_bucket.assert_called_once_with(tableBucketARN=BUCKET_ARN)
+
+    def test_template_fields(self):
+        validate_template_fields(self.operator)