Skip to content

Commit b489ca4

Browse files
committed
Merge branch 'main' into feat/docsite-agent-improvements
2 parents ed21f8d + e0284c6 commit b489ca4

8 files changed

Lines changed: 893 additions & 193 deletions

File tree

.ai/skills/make-pythonic/SKILL.md

Lines changed: 430 additions & 0 deletions
Large diffs are not rendered by default.

pyproject.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,7 @@ extend-allowed-calls = ["datafusion.lit", "lit"]
111111
"ARG",
112112
"BLE001",
113113
"D",
114+
"FBT003",
114115
"PD",
115116
"PLC0415",
116117
"PLR0913",

python/datafusion/expr.py

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -243,6 +243,8 @@
243243
"WindowExpr",
244244
"WindowFrame",
245245
"WindowFrameBound",
246+
"coerce_to_expr",
247+
"coerce_to_expr_or_none",
246248
"ensure_expr",
247249
"ensure_expr_list",
248250
]
@@ -255,6 +257,10 @@ def ensure_expr(value: Expr | Any) -> expr_internal.Expr:
255257
higher level APIs consistently require explicit :func:`~datafusion.col` or
256258
:func:`~datafusion.lit` expressions.
257259
260+
See Also:
261+
:func:`coerce_to_expr` — the opposite behavior: *wraps* non-``Expr``
262+
values as literals instead of rejecting them.
263+
258264
Args:
259265
value: Candidate expression or other object.
260266
@@ -299,6 +305,41 @@ def _iter(
299305
return list(_iter(exprs))
300306

301307

308+
def coerce_to_expr(value: Any) -> Expr:
309+
"""Coerce a native Python value to an ``Expr`` literal, passing ``Expr`` through.
310+
311+
This is the complement of :func:`ensure_expr`: where ``ensure_expr``
312+
*rejects* non-``Expr`` values, ``coerce_to_expr`` *wraps* them via
313+
:meth:`Expr.literal` so that functions can accept native Python types
314+
(``int``, ``float``, ``str``, ``bool``, etc.) alongside ``Expr``.
315+
316+
Args:
317+
value: An ``Expr`` instance (returned as-is) or a Python literal to wrap.
318+
319+
Returns:
320+
An ``Expr`` representing the value.
321+
"""
322+
if isinstance(value, Expr):
323+
return value
324+
return Expr.literal(value)
325+
326+
327+
def coerce_to_expr_or_none(value: Any | None) -> Expr | None:
328+
"""Coerce a value to ``Expr`` or pass ``None`` through unchanged.
329+
330+
Same as :func:`coerce_to_expr` but accepts ``None`` for optional parameters.
331+
332+
Args:
333+
value: An ``Expr`` instance, a Python literal to wrap, or ``None``.
334+
335+
Returns:
336+
An ``Expr`` representing the value, or ``None``.
337+
"""
338+
if value is None:
339+
return None
340+
return coerce_to_expr(value)
341+
342+
302343
def _to_raw_expr(value: Expr | str) -> expr_internal.Expr:
303344
"""Convert a Python expression or column name to its raw variant.
304345

0 commit comments

Comments
 (0)