Skip to content

Fix custom function input not binding positionally when column name d… - #1166

Open
mborodii-prog wants to merge 3 commits into
mainfrom
fix/issue-747-custom-function-positional-input
Open

Fix custom function input not binding positionally when column name d…#1166
mborodii-prog wants to merge 3 commits into
mainfrom
fix/issue-747-custom-function-positional-input

Conversation

@mborodii-prog

@mborodii-prog mborodii-prog commented Sep 4, 2026

Copy link
Copy Markdown
Contributor

Summary

Fixes #747 — custom row-wise functions silently dropped a column's value whenever it didn't exactly match one of the function's parameter names, producing a confusing TypeError instead of resolving the function's other parameters against their defaults.

  • Row-wise custom functions previously bound columns to parameters only by exact name equality (or via **kwargs). If a column's name didn't match a parameter name, its value was discarded entirely and the function was called without it.
  • Now, when none of the available column(s) match a parameter by name they fall back to binding positionally, in the function's declared parameter order, to whichever parameters aren't already supplied explicitly — whether the columns came from an explicit input: or from the dataframe as a whole when input: isn't given at all.
  • When there are more unmatched columns than the function has room for, it's ambiguous which ones to use — instead of guessing (or falling through to a misleading "missing argument" error), this now raises a clear ValueError naming exactly what's expected vs. what was given.

Examples

def func(x, y="default", z="default"):
    return f"{x}-{y}-{z}"

1. Mismatched column name via input:

wrangles:
  - custom.func:
      input: my_col
      output: result
Before After
Column my_col → param x, y/z default TypeError: func() missing 1 required positional argument: 'x' result = "row1-default-default"

2. Mismatched column, no input: at all

wrangles:
  - custom.func:
      output: result

Dataframe has one column my_col (no name match) → same result as above,
result = "row1-default-default". Previously this also failed the same way.

3. Multiple mismatched columns bind positionally, in order

wrangles:
  - custom.func:
      output: result
Columns present Binding result
col_a col_a → x; y/z default "col_a_v1-default-default"
col_a, col_b col_a → x, col_b → y; z default "col_a_v1-col_b_v1-default"
col_a, col_b, col_c col_a → x, col_b → y, col_c → z "col_a_v1-col_b_v1-col_c_v1"

4. Too many unmatched columns → clear error

wrangles:
  - custom.func:
      output: result

Dataframe has 4 columns (a, b, c, d) for a 3-parameter function:

Before After
4 columns, 3 params TypeError: func() missing 1 required positional argument: 'x' (misleading — implies something's missing, not that too much was given) ValueError: custom.func accepts at most 3 unfilled parameter(s) (x, y, z) but 4 column(s) were provided: a, b, c, d

The fallback only ever engages when there's zero name-based match, so existing name-matching and literal input/output-as-parameter behavior is unchanged.

Changes

  • wrangles/recipe.py: positional-binding fallback and too-many-columns guard in the row-wise custom-function dispatch (_execute_wrangles).
  • tests/recipes/test_custom_functions.py: regression tests for each of the four scenarios above.
  • tests/recipes/wrangles/test_extract.py: unrelated flaky-test fix — test_ai_invalid_model_per_row_error was pinned to status=400 for an unknown model, but OpenAI now reports that as 404 model_not_found; relaxed to accept any 4xx client error.

mborodii-prog and others added 3 commits September 4, 2026 12:35
…oesn't match a parameter (#747)

Row-wise custom functions only bound values to parameters by exact
column-name/parameter-name equality. When `input:` mapped a column to
a function whose parameter names didn't match (e.g. func(x, y="default",
z="default") fed by a column named something else), the value was
silently dropped and the function was called without it, surfacing as
a missing-argument TypeError instead of resolving the trailing defaults.

Falls back to binding unmatched input column(s) positionally to the
function's remaining unfilled parameters, in declared order, only when
no name-based match exists at all - preserving existing name-matching
and literal input/output-as-parameter behavior.
Apply the same positional-binding fallback introduced for #747 even
when `input:` isn't specified at all - as long as none of the
dataframe's columns match the function's parameter names, and their
count fits within the function's remaining unfilled parameters, they
now bind positionally in declared order instead of only working when
`input:` explicitly names the mismatched column(s).

Also relax an unrelated flaky assertion in
test_ai_invalid_model_per_row_error: OpenAI now reports an unknown
model as a 404 model_not_found rather than the 400 this test assumed,
so check for any 4xx client error instead of pinning to one code.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014sPSwydeh9Juqhr5nRvL9i
@mborodii-prog
mborodii-prog marked this pull request as ready for review September 4, 2026 13:33
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Custom Functions: Positional based not working correctly with kwargs/parameter defaults

1 participant