@@ -1054,29 +1054,6 @@ def from_pycapsule(func: WindowUDFExportable) -> WindowUDF:
10541054 )
10551055
10561056
1057- def _callable_accepts_session_kwarg (func : object ) -> bool :
1058- """Return True if ``func`` accepts a ``session`` keyword argument.
1059-
1060- Used to opt a Python UDTF callback into receiving the calling
1061- :class:`SessionContext` at invocation time. ``**kwargs`` callables
1062- are treated as accepting it; built-ins and objects without an
1063- introspectable signature fall back to ``False``.
1064- """
1065- import inspect # noqa: PLC0415
1066-
1067- try :
1068- signature = inspect .signature (func )
1069- except (TypeError , ValueError ):
1070- return False
1071-
1072- for parameter in signature .parameters .values ():
1073- if parameter .name == "session" :
1074- return True
1075- if parameter .kind is inspect .Parameter .VAR_KEYWORD :
1076- return True
1077- return False
1078-
1079-
10801057def _wrap_session_kwarg_for_udtf (func : Callable [..., Any ]) -> Callable [..., Any ]:
10811058 """Adapt the raw internal session pyo3 object back to a Python wrapper.
10821059
@@ -1103,23 +1080,27 @@ class TableFunction:
11031080 """
11041081
11051082 def __init__ (
1106- self , name : str , func : Callable [[], any ], ctx : SessionContext | None = None
1083+ self ,
1084+ name : str ,
1085+ func : Callable [..., Any ],
1086+ ctx : SessionContext | None = None ,
1087+ * ,
1088+ with_session : bool = False ,
11071089 ) -> None :
11081090 """Instantiate a user-defined table function (UDTF).
11091091
1110- If ``func``'s signature accepts a ``session`` keyword (or
1111- ``**kwargs``), the calling :class:`SessionContext` is threaded
1112- through to it on each invocation. Use it inside the body to look
1113- up registered tables, UDFs, or session configuration. Callables
1114- whose signatures do not declare ``session `` are invoked with the
1115- positional expression arguments only.
1092+ Set ``with_session=True`` to have the calling
1093+ :class:`SessionContext` passed as a ``session`` keyword argument
1094+ on each invocation. Use it inside the callback to look up
1095+ registered tables, UDFs, or session configuration. When
1096+ ``with_session`` is ``False`` (the default), ``func `` is invoked
1097+ with the positional expression arguments only.
11161098
11171099 See :py:func:`udtf` for a convenience function and argument
11181100 descriptions.
11191101 """
1120- accepts_session = _callable_accepts_session_kwarg (func )
1121- registered = _wrap_session_kwarg_for_udtf (func ) if accepts_session else func
1122- self ._udtf = df_internal .TableFunction (name , registered , ctx , accepts_session )
1102+ registered = _wrap_session_kwarg_for_udtf (func ) if with_session else func
1103+ self ._udtf = df_internal .TableFunction (name , registered , ctx , with_session )
11231104
11241105 def __call__ (self , * args : Expr ) -> Any :
11251106 """Execute the UDTF and return a table provider."""
@@ -1130,47 +1111,66 @@ def __call__(self, *args: Expr) -> Any:
11301111 @staticmethod
11311112 def udtf (
11321113 name : str ,
1114+ * ,
1115+ with_session : bool = False ,
11331116 ) -> Callable [..., Any ]: ...
11341117
11351118 @overload
11361119 @staticmethod
11371120 def udtf (
1138- func : Callable [[] , Any ],
1121+ func : Callable [... , Any ],
11391122 name : str ,
1123+ * ,
1124+ with_session : bool = False ,
11401125 ) -> TableFunction : ...
11411126
11421127 @staticmethod
1143- def udtf (* args : Any , ** kwargs : Any ):
1144- """Create a new User-Defined Table Function (UDTF)."""
1128+ def udtf (* args : Any , with_session : bool = False , ** kwargs : Any ):
1129+ """Create a new User-Defined Table Function (UDTF).
1130+
1131+ Pass ``with_session=True`` to have the calling
1132+ :class:`SessionContext` injected as a ``session`` keyword
1133+ argument on each invocation.
1134+ """
11451135 if args and callable (args [0 ]):
11461136 # Case 1: Used as a function, require the first parameter to be callable
1147- return TableFunction ._create_table_udf (* args , ** kwargs )
1137+ return TableFunction ._create_table_udf (
1138+ * args , with_session = with_session , ** kwargs
1139+ )
11481140 if args and hasattr (args [0 ], "__datafusion_table_function__" ):
11491141 # Case 2: We have a datafusion FFI provided function
11501142 return TableFunction (args [1 ], args [0 ])
11511143 # Case 3: Used as a decorator with parameters
1152- return TableFunction ._create_table_udf_decorator (* args , ** kwargs )
1144+ return TableFunction ._create_table_udf_decorator (
1145+ * args , with_session = with_session , ** kwargs
1146+ )
11531147
11541148 @staticmethod
11551149 def _create_table_udf (
11561150 func : Callable [..., Any ],
11571151 name : str ,
1152+ * ,
1153+ with_session : bool = False ,
11581154 ) -> TableFunction :
11591155 """Create a TableFunction instance from function arguments."""
11601156 if not callable (func ):
11611157 msg = "`func` must be callable."
11621158 raise TypeError (msg )
11631159
1164- return TableFunction (name , func )
1160+ return TableFunction (name , func , with_session = with_session )
11651161
11661162 @staticmethod
11671163 def _create_table_udf_decorator (
11681164 name : str | None = None ,
1169- ) -> Callable [[Callable [[], WindowEvaluator ]], Callable [..., Expr ]]:
1170- """Create a decorator for a WindowUDF."""
1171-
1172- def decorator (func : Callable [[], WindowEvaluator ]) -> Callable [..., Expr ]:
1173- return TableFunction ._create_table_udf (func , name )
1165+ * ,
1166+ with_session : bool = False ,
1167+ ) -> Callable [[Callable [..., Any ]], TableFunction ]:
1168+ """Create a decorator for a TableFunction."""
1169+
1170+ def decorator (func : Callable [..., Any ]) -> TableFunction :
1171+ return TableFunction ._create_table_udf (
1172+ func , name , with_session = with_session
1173+ )
11741174
11751175 return decorator
11761176
0 commit comments