This is an automated email from the ASF dual-hosted git repository.
henry3260 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 7fed0f07cf0 Fix Hive metastore partition sensor initialization (#69612)
7fed0f07cf0 is described below
commit 7fed0f07cf0b79159296b1d6e6ec8641a94d6ec6
Author: Henry Chen <[email protected]>
AuthorDate: Wed Jul 15 20:00:26 2026 +0800
Fix Hive metastore partition sensor initialization (#69612)
---
.../apache/hive/sensors/metastore_partition.py | 53 ++++++++++++----------
.../hive/sensors/test_metastore_partition.py | 51 ++++++++++++++++++++-
2 files changed, 79 insertions(+), 25 deletions(-)
diff --git
a/providers/apache/hive/src/airflow/providers/apache/hive/sensors/metastore_partition.py
b/providers/apache/hive/src/airflow/providers/apache/hive/sensors/metastore_partition.py
index 6b3abee572c..d6c375795de 100644
---
a/providers/apache/hive/src/airflow/providers/apache/hive/sensors/metastore_partition.py
+++
b/providers/apache/hive/src/airflow/providers/apache/hive/sensors/metastore_partition.py
@@ -26,6 +26,18 @@ if TYPE_CHECKING:
from airflow.providers.common.compat.sdk import Context
+_METASTORE_PARTITION_SQL = """
+SELECT 'X'
+FROM PARTITIONS A0
+LEFT OUTER JOIN TBLS B0 ON A0.TBL_ID = B0.TBL_ID
+LEFT OUTER JOIN DBS C0 ON B0.DB_ID = C0.DB_ID
+WHERE
+ B0.TBL_NAME = %(table)s AND
+ C0.NAME = %(schema)s AND
+ A0.PART_NAME = %(partition_name)s;
+"""
+
+
class MetastorePartitionSensor(SqlSensor):
"""
An alternative to the HivePartitionSensor that talk directly to the MySQL
db.
@@ -43,7 +55,7 @@ class MetastorePartitionSensor(SqlSensor):
:param mysql_conn_id: a reference to the MySQL conn_id for the metastore
"""
- template_fields: Sequence[str] = ("partition_name", "table", "schema")
+ template_fields: Sequence[str] = (*SqlSensor.template_fields,
"partition_name", "table", "schema")
ui_color = "#8da7be"
def __init__(
@@ -58,28 +70,23 @@ class MetastorePartitionSensor(SqlSensor):
self.partition_name = partition_name
self.table = table
self.schema = schema
- self.first_poke = True
- self.conn_id = mysql_conn_id
- # TODO(aoen): We shouldn't be using SqlSensor here but
MetastorePartitionSensor.
- # The problem is the way apply_defaults works isn't compatible with
inheritance.
- # The inheritance model needs to be reworked in order to support
overriding args/
- # kwargs with arguments here, then 'conn_id' and 'sql' can be passed
into the
- # constructor below and apply_defaults will no longer throw an
exception.
- super().__init__(**kwargs)
+ _kwargs: dict[str, Any] = {"conn_id": mysql_conn_id, "sql":
_METASTORE_PARTITION_SQL}
+ if kwargs:
+ _kwargs |= kwargs
+ super().__init__(**_kwargs)
def poke(self, context: Context) -> Any:
- if self.first_poke:
- self.first_poke = False
- if "." in self.table:
- self.schema, self.table = self.table.split(".")
- self.sql = f"""
- SELECT 'X'
- FROM PARTITIONS A0
- LEFT OUTER JOIN TBLS B0 ON A0.TBL_ID = B0.TBL_ID
- LEFT OUTER JOIN DBS C0 ON B0.DB_ID = C0.DB_ID
- WHERE
- B0.TBL_NAME = '{self.table}' AND
- C0.NAME = '{self.schema}' AND
- A0.PART_NAME = '{self.partition_name}';
- """
+ if "." in self.table:
+ parts = self.table.split(".")
+ if len(parts) != 2:
+ raise ValueError(f"Expected 'schema.table' format, got:
{self.table!r}")
+ schema, table = parts
+ else:
+ schema, table = self.schema, self.table
+
+ self.parameters = {
+ "table": table,
+ "schema": schema,
+ "partition_name": self.partition_name,
+ }
return super().poke(context)
diff --git
a/providers/apache/hive/tests/unit/apache/hive/sensors/test_metastore_partition.py
b/providers/apache/hive/tests/unit/apache/hive/sensors/test_metastore_partition.py
index 743bdc03a53..58d5ea7d7f5 100644
---
a/providers/apache/hive/tests/unit/apache/hive/sensors/test_metastore_partition.py
+++
b/providers/apache/hive/tests/unit/apache/hive/sensors/test_metastore_partition.py
@@ -27,6 +27,54 @@ from
airflow.providers.apache.hive.sensors.metastore_partition import MetastoreP
from unit.apache.hive import DEFAULT_DATE, DEFAULT_DATE_DS, MockDBConnection,
TestHiveEnvironment
[email protected](
+ ("table", "schema", "expected_parameters"),
+ [
+ (
+ "airflow.static_babynames_partitioned",
+ "default",
+ {
+ "table": "static_babynames_partitioned",
+ "schema": "airflow",
+ "partition_name": f"ds={DEFAULT_DATE_DS}",
+ },
+ ),
+ (
+ "static_babynames_partitioned",
+ "airflow",
+ {
+ "table": "static_babynames_partitioned",
+ "schema": "airflow",
+ "partition_name": f"ds={DEFAULT_DATE_DS}",
+ },
+ ),
+ ],
+)
+def test_metastore_partition_sensor_uses_documented_constructor_and_parameters(
+ table, schema, expected_parameters
+):
+ op = MetastorePartitionSensor(
+ task_id="hive_partition_check",
+ mysql_conn_id="test_connection_id",
+ table=table,
+ schema=schema,
+ partition_name=f"ds={DEFAULT_DATE_DS}",
+ )
+ hook = mock.MagicMock()
+ hook.get_records.return_value = [["test_record"]]
+ op._get_hook = mock.MagicMock(return_value=hook)
+
+ assert op.conn_id == "test_connection_id"
+ assert op.poke({}) is True
+
+ hook.get_records.assert_called_once()
+ sql, parameters = hook.get_records.call_args.args
+ assert "B0.TBL_NAME = %(table)s" in sql
+ assert "C0.NAME = %(schema)s" in sql
+ assert "A0.PART_NAME = %(partition_name)s" in sql
+ assert parameters == expected_parameters
+
+
@pytest.mark.skipif(
"AIRFLOW_RUNALL_TESTS" not in os.environ, reason="Skipped because
AIRFLOW_RUNALL_TESTS is not set"
)
@@ -34,8 +82,7 @@ class TestHivePartitionSensor(TestHiveEnvironment):
def test_hive_metastore_sql_sensor(self):
op = MetastorePartitionSensor(
task_id="hive_partition_check",
- conn_id="test_connection_id",
- sql="test_sql",
+ mysql_conn_id="test_connection_id",
table="airflow.static_babynames_partitioned",
partition_name=f"ds={DEFAULT_DATE_DS}",
dag=self.dag,