This is an automated email from the ASF dual-hosted git repository.
dianfu pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/flink.git
The following commit(s) were added to refs/heads/master by this push:
new aced6782c11 [FLINK-40986][python] Make named Row hashing consistent
with equality (#29472)
aced6782c11 is described below
commit aced6782c114b0b9deab309e17765335459bd77a
Author: Biao Geng <[email protected]>
AuthorDate: Wed Oct 14 13:20:38 2026 +0800
[FLINK-40986][python] Make named Row hashing consistent with equality
(#29472)
---
flink-python/pyflink/common/tests/test_types.py | 71 +++++++++++++++++++++++++
flink-python/pyflink/common/types.py | 2 +
2 files changed, 73 insertions(+)
diff --git a/flink-python/pyflink/common/tests/test_types.py
b/flink-python/pyflink/common/tests/test_types.py
new file mode 100644
index 00000000000..50d462d8986
--- /dev/null
+++ b/flink-python/pyflink/common/tests/test_types.py
@@ -0,0 +1,71 @@
+################################################################################
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+################################################################################
+
+import unittest
+
+from pyflink.common import Row, RowKind
+
+
+class RowTests(unittest.TestCase):
+
+ def test_named_row_hash(self):
+ for row_kind in RowKind:
+ for other in [Row(b=2, a=1), Row('b', 'a')(2, 1)]:
+ with self.subTest(row_kind=row_kind, other=other):
+ row = Row(a=1, b=2)
+ row.set_row_kind(row_kind)
+ other.set_row_kind(row_kind)
+ self.assertEqual(row, other)
+ self.assertEqual(hash(row), hash(other))
+ self.assertEqual(tuple(other), (2, 1))
+ self.assertEqual(list(other.as_dict()), ['b', 'a'])
+
+ def test_named_row_set(self):
+ self.assertEqual(len({Row(a=1, b=2), Row(b=2, a=1)}), 1)
+
+ def test_named_row_dict(self):
+ values = {Row(a=1, b=2): 'value'}
+ self.assertEqual(values[Row(b=2, a=1)], 'value')
+ values[Row(b=2, a=1)] = 'updated'
+ self.assertEqual(len(values), 1)
+ self.assertEqual(values[Row(a=1, b=2)], 'updated')
+
+ def test_positional_row_hash(self):
+ for values in [(), (1, 2), (2, 1)]:
+ with self.subTest(values=values):
+ self.assertEqual(hash(Row(*values)), hash(values))
+ self.assertEqual(len({Row(*values), Row(*values)}), 1)
+ self.assertEqual(len({Row(1, 2), Row(2, 1)}), 2)
+
+ def test_nested_row_hash(self):
+ row = Row(a=Row(x=1, y=2), b=3)
+ other = Row(b=3, a=Row(y=2, x=1))
+ self.assertEqual(row, other)
+ self.assertEqual(hash(row), hash(other))
+ self.assertEqual(len({row, other}), 1)
+
+ def test_unhashable_row_fields(self):
+ for value in [[1, 2], {'a': 1}]:
+ for row in [Row(value), Row(a=value)]:
+ with self.subTest(row=row):
+ with self.assertRaises(TypeError):
+ hash(row)
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/flink-python/pyflink/common/types.py
b/flink-python/pyflink/common/types.py
index 894a4e89cd2..2547266581a 100644
--- a/flink-python/pyflink/common/types.py
+++ b/flink-python/pyflink/common/types.py
@@ -278,6 +278,8 @@ class Row(object):
self._values == other._values)
def __hash__(self):
+ if hasattr(self, "_fields"):
+ return hash(frozenset(zip(self._fields, self._values)))
return tuple(self).__hash__()
def __iter__(self):