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

timsaucer pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/datafusion-python.git


The following commit(s) were added to refs/heads/main by this push:
     new c9f15547 feat: alias with metadata (#1111)
c9f15547 is described below

commit c9f15547cb8019068bbf2dc8eaf148d6eb42bd48
Author: Chen Chongchen <[email protected]>
AuthorDate: Fri Apr 25 21:01:54 2025 +0800

    feat: alias with metadata (#1111)
    
    * feat: alias with metadata
    
    * fmt
---
 python/datafusion/expr.py      | 14 +++++++++++---
 python/datafusion/functions.py | 15 ++++++++++++---
 python/tests/test_expr.py      |  5 +++++
 python/tests/test_functions.py |  5 +++++
 src/expr.rs                    |  6 ++++--
 src/functions.rs               |  9 +++++++--
 6 files changed, 44 insertions(+), 10 deletions(-)

diff --git a/python/datafusion/expr.py b/python/datafusion/expr.py
index 2697d814..01e1f3de 100644
--- a/python/datafusion/expr.py
+++ b/python/datafusion/expr.py
@@ -406,9 +406,17 @@ class Expr:
         """Creates a new expression representing a column."""
         return Expr(expr_internal.RawExpr.column(value))
 
-    def alias(self, name: str) -> Expr:
-        """Assign a name to the expression."""
-        return Expr(self.expr.alias(name))
+    def alias(self, name: str, metadata: Optional[dict[str, str]] = None) -> 
Expr:
+        """Assign a name to the expression.
+
+        Args:
+            name: The name to assign to the expression.
+            metadata: Optional metadata to attach to the expression.
+
+        Returns:
+            A new expression with the assigned name.
+        """
+        return Expr(self.expr.alias(name, metadata))
 
     def sort(self, ascending: bool = True, nulls_first: bool = True) -> 
SortExpr:
         """Creates a sort :py:class:`Expr` from an existing :py:class:`Expr`.
diff --git a/python/datafusion/functions.py b/python/datafusion/functions.py
index 5cf914e1..f430cdf4 100644
--- a/python/datafusion/functions.py
+++ b/python/datafusion/functions.py
@@ -372,9 +372,18 @@ def order_by(expr: Expr, ascending: bool = True, 
nulls_first: bool = True) -> So
     return SortExpr(expr, ascending=ascending, nulls_first=nulls_first)
 
 
-def alias(expr: Expr, name: str) -> Expr:
-    """Creates an alias expression."""
-    return Expr(f.alias(expr.expr, name))
+def alias(expr: Expr, name: str, metadata: Optional[dict[str, str]] = None) -> 
Expr:
+    """Creates an alias expression with an optional metadata dictionary.
+
+    Args:
+        expr: The expression to alias
+        name: The alias name
+        metadata: Optional metadata to attach to the column
+
+    Returns:
+        An expression with the given alias
+    """
+    return Expr(f.alias(expr.expr, name, metadata))
 
 
 def col(name: str) -> Expr:
diff --git a/python/tests/test_expr.py b/python/tests/test_expr.py
index 926e6984..dcf75f02 100644
--- a/python/tests/test_expr.py
+++ b/python/tests/test_expr.py
@@ -247,3 +247,8 @@ def test_fill_null(df):
     assert result.column(0) == pa.array([1, 2, 100])
     assert result.column(1) == pa.array([4, 25, 6])
     assert result.column(2) == pa.array([1234, 1234, 8])
+
+
+def test_alias_with_metadata(df):
+    df = df.select(col("a").alias("b", {"key": "value"}))
+    assert df.schema().field("b").metadata == {b"key": b"value"}
diff --git a/python/tests/test_functions.py b/python/tests/test_functions.py
index 37f2075f..90cf01f7 100644
--- a/python/tests/test_functions.py
+++ b/python/tests/test_functions.py
@@ -1231,3 +1231,8 @@ def test_between_default(df):
 
     actual = df.collect()[0].to_pydict()
     assert actual == expected
+
+
+def test_alias_with_metadata(df):
+    df = df.select(f.alias(f.col("a"), "b", {"key": "value"}))
+    assert df.schema().field("b").metadata == {b"key": b"value"}
diff --git a/src/expr.rs b/src/expr.rs
index fe0e76da..7d4aa879 100644
--- a/src/expr.rs
+++ b/src/expr.rs
@@ -22,6 +22,7 @@ use datafusion::logical_expr::{
 };
 use pyo3::IntoPyObjectExt;
 use pyo3::{basic::CompareOp, prelude::*};
+use std::collections::HashMap;
 use std::convert::{From, Into};
 use std::sync::Arc;
 use window::PyWindowFrame;
@@ -275,8 +276,9 @@ impl PyExpr {
     }
 
     /// assign a name to the PyExpr
-    pub fn alias(&self, name: &str) -> PyExpr {
-        self.expr.clone().alias(name).into()
+    #[pyo3(signature = (name, metadata=None))]
+    pub fn alias(&self, name: &str, metadata: Option<HashMap<String, String>>) 
-> PyExpr {
+        self.expr.clone().alias_with_metadata(name, metadata).into()
     }
 
     /// Create a sort PyExpr from an existing PyExpr.
diff --git a/src/functions.rs b/src/functions.rs
index 476c2b80..caa79b8a 100644
--- a/src/functions.rs
+++ b/src/functions.rs
@@ -15,6 +15,8 @@
 // specific language governing permissions and limitations
 // under the License.
 
+use std::collections::HashMap;
+
 use datafusion::functions_aggregate::all_default_aggregate_functions;
 use datafusion::functions_window::all_default_window_functions;
 use datafusion::logical_expr::expr::WindowFunctionParams;
@@ -205,10 +207,13 @@ fn order_by(expr: PyExpr, asc: bool, nulls_first: bool) 
-> PyResult<PySortExpr>
 
 /// Creates a new Alias Expr
 #[pyfunction]
-fn alias(expr: PyExpr, name: &str) -> PyResult<PyExpr> {
+#[pyo3(signature = (expr, name, metadata=None))]
+fn alias(expr: PyExpr, name: &str, metadata: Option<HashMap<String, String>>) 
-> PyResult<PyExpr> {
     let relation: Option<TableReference> = None;
     Ok(PyExpr {
-        expr: datafusion::logical_expr::Expr::Alias(Alias::new(expr.expr, 
relation, name)),
+        expr: datafusion::logical_expr::Expr::Alias(
+            Alias::new(expr.expr, relation, name).with_metadata(metadata),
+        ),
     })
 }
 


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to