eugenegujing opened a new pull request, #7761:
URL: https://github.com/apache/texera/pull/7761
### What changes were proposed in this PR?
`pytexera/udf/examples/join_operator.py` — the shipped hash-join example and
the only dual-input example operator — emits a match with `yield left_tuple +
tuple_`, but `core.models.Tuple` implements no `__add__`/`__radd__`, so every
join match raises `TypeError: unsupported operand type(s) for +: 'Tuple' and
'Tuple'`. The only output-producing branch of the example has never worked; a
user who copies this example into a dual-input Python UDF gets a crash on the
first match.
This PR replaces the `+` with an explicit dict merge:
```python
# join and output; on duplicate column names the
# probe (right) side's value wins
yield {**left_tuple.as_dict(), **tuple_.as_dict()}
```
Yielding a plain dict is the established idiom in the sibling examples
(`generator_operator_integer.py` / `generator_operator_binary.py` already do
it). The merge implies a collision policy — on duplicate column names the probe
(right) side's value wins, while left columns keep their order and position —
and the new comment records that decision explicitly instead of hiding it.
### Any related issues, documentation, discussions?
Closes #7759
### How was this PR tested?
`join_operator.py` was the only example operator without a spec. This PR
adds `amber/src/test/python/pytexera/udf/examples/test_join_operator.py`,
written before the fix (TDD) — the three match-producing tests fail with the
exact TypeError against the unfixed code. 12 tests total:
- one match emits exactly one merged tuple containing all columns from both
sides
- a probe tuple with no matching key emits nothing
- duplicate build-side keys emit one merged output per stored left tuple, in
insertion order
- two build rows × two probe rows on the same key emit four merged outputs
- build-side (port 0) tuples emit nothing
- probing an empty build side emits nothing
- on colliding column names the probe side's value wins (asserted via a
shared non-key column, since the `key` values are equal on any match by
definition)
- merged output column order: left columns keep their order and position
(collided columns included), probe-only columns are appended
- `None` keys join each other (pins the current behavior, which diverges
from SQL NULL semantics — `None` is an ordinary hashable dict key in Python)
- an emitted output does not alias the stored build-side data (mutating an
output cannot corrupt later matches)
- an `int` key matches an equal `float` key (Python cross-type numeric
equality); an `int` key does not match its string form
Run with:
```
cd amber && pytest src/test/python/pytexera/udf/examples/ -v
```
→ 23 passed (12 new + 11 pre-existing example tests). The spec was also
mutation-checked: reverting the fix, swapping the merge order, probing only the
first match, making the build branch yield, type-strict key matching, skipping
`None` keys, and an aliasing stored-dict implementation each cause the intended
test(s) to fail. The end-to-end behavior was additionally verified in the UI
with a two-source workflow feeding a `DualInputPortsPythonUDFV2`: the verbatim
example code crashes with the TypeError above, and the fixed code emits the
expected single merged row.
### Was this PR authored or co-authored using generative AI tooling?
Generated-by: Claude Code (Claude Fable 5)
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]