Skip to content

Fix wildcard columns not matching when combined with optional (?) - #1155

Merged
ebhills merged 1 commit into
mainfrom
fix/Optional-output-does-not-work-with-wildcard
Sep 1, 2026
Merged

Fix wildcard columns not matching when combined with optional (?)#1155
ebhills merged 1 commit into
mainfrom
fix/Optional-output-does-not-work-with-wildcard

Conversation

@mborodii-prog

Copy link
Copy Markdown
Contributor

Fix wildcard columns not matching when combined with optional (?)

Problem

write:
  - file:
      name: file.xlsx
      columns:
        - Col*?

Any column selector combining a wildcard (*) with the optional marker (?) matched nothing, silently — the columns were just missing from the output, with no error.

Root cause

wildcard_expansion() converts * patterns into escaped regex before checking for the trailing ? optional marker. So Col*? got turned into the regex Col(.*)\?, which requires the column name to literally end in a question mark character — never true for a real column — instead of being recognized as "wildcard Col*, marked optional."

>>> from wrangles.utils import wildcard_expansion
>>> wildcard_expansion(['Col1', 'Col2', 'Other'], ['Col*'])
['Col1', 'Col2']          # works fine on its own
>>> wildcard_expansion(['Col1', 'Col2', 'Other'], ['Col*?'])
KeyError: 'Wildcard expansion pattern did not find any matching columns'

Fix

  1. Strip the ? marker before the *→regex conversion, and track optionality per-entry so a wildcard that matches zero columns is treated like a missing optional column (no error) instead of guaranteed to match nothing.
>>> wildcard_expansion(['Col1', 'Col2', 'Other'], ['Col*?'])
['Col1', 'Col2']                          # now expands correctly
>>> wildcard_expansion(['Col1', 'Col2'], ['NoMatch*?'])
[]                                        # optional + zero matches = no error
>>> wildcard_expansion(['Col1', 'Col2'], ['NoMatch*'])
KeyError: 'Wildcard expansion pattern did not find any matching columns'   # non-optional still errors, unchanged
  1. Second bug found while testing the first fix: wildcard_expansion() gets called twice on the same columns list within a single write step (once generically in recipe.py, again inside the file connector). The original code's optional-handling used a local variable and never mutated the caller's list, so this double-call was always safe. My first attempt at fix Allow setting credentials with environment variables #1 mutated the list in place to strip ?, which broke the second call — it saw the marker already gone and raised anyway.
>>> cols = ['Find', 'Replace', 'find?']
>>> wildcard_expansion(['Find', 'Replace'], cols)
['Find', 'Replace']
>>> cols   # before this fix: mutated to ['Find', 'Replace', 'find'] - lost the "optional" marker
['Find', 'Replace', 'find?']   # now: untouched, safe to call again
>>> wildcard_expansion(['Find', 'Replace'], cols)   # second call, same list
['Find', 'Replace']   # still correct

Fixed by having the function operate on an internal copy — it no longer mutates the caller's list under any circumstance, regardless of how many times it's called with the same input.

Tests

Added to tests/connectors/test_file.py:

  • test_write_file_optional_wildcard_col_matchesFi*? against a 2-column file correctly writes only the matching column.
  • test_write_file_optional_wildcard_col_no_matchesNoSuchColumn*? alongside a real column writes only the real column, no error.

Both read back the actual written file rather than trusting recipe.run()'s return value, since write-step column filtering is a side effect on the output file, not on the pipeline dataframe.

@mborodii-prog mborodii-prog linked an issue Aug 31, 2026 that may be closed by this pull request
@ebhills
ebhills merged commit 3aaad59 into main Sep 1, 2026
13 checks passed
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.

Optional output does not work with wildcard Allow setting credentials with environment variables

2 participants