eugenegujing opened a new pull request, #6278:
URL: https://github.com/apache/texera/pull/6278

   ### What changes were proposed in this PR?
   
   Pandas-based Python operators naturally produce **numpy scalar types** at 
the `Tuple` output boundary, and the Python worker rejects them:
   
   - `df["x"].sum()` / `.max()` / `.count()` return `numpy.int64`
   - `df["x"].any()` or any numpy comparison returns `numpy.bool_`
   
   On output, `Tuple.finalize(schema)` runs `cast_to_schema()` then a strict 
`isinstance(value, expected_python_type)` check in `validate_schema()`. Because 
numpy's integer and bool scalar types are **not** subclasses of Python `int` / 
`bool` (`isinstance(np.int64(5), int)` and `isinstance(np.bool_(True), bool)` 
are both `False`), the check fails and the operator crashes with `TypeError: 
Unmatched type for field ...`, even though the value is semantically correct 
(`np.int64(5)` is exactly the integer 5; the field is declared INTEGER).
   
   This is a direct follow-up to #6053, which added `float → int` coercion for 
INT/LONG fields. That fix only handled `np.float64` (which happens to subclass 
Python `float`); numpy integer and bool scalars were still rejected. This PR 
extends the same mechanism in `cast_to_schema()` to cover them:
   
   - **INT/LONG fields:** accept `numpy.integer` scalars by normalizing them 
(and integral floats) into a candidate `int`, then applying the existing 
`INTEGRAL_TYPE_RANGES` bounds check once. `int()` is exact for numpy integers, 
so there is no precision loss. Out-of-range values are left unchanged so 
`validate_schema()` still fails loudly (no int32 overflow / silent corruption).
   - **BOOL fields:** convert `numpy.bool_` to Python `bool` in a separate 
branch gated on the BOOL target type, so `bool` and `int` never cross-coerce 
(`np.bool_` is not `numpy.integer`, and a plain Python `bool` — an `int` 
subclass — is never coerced into an integer field).
   
   `validate_schema()` is unchanged; it remains the strict backstop, so any 
type this PR does not explicitly coerce still fails loudly rather than passing 
silently.
   
   **Out of scope:** `np.float32` is not a Python `float` subclass, so an 
integral `np.float32` into an INT field is still rejected. It is intentionally 
left out of this PR to keep the change focused; it can be folded into the same 
float-normalization path in a follow-up if desired.
   
   ### Any related issues, documentation, discussions?
   
   - Fixes #6277
   - Follow-up to #6053 (integral `float → int` coercion for INT/LONG fields).
   
   ### How was this PR tested?
   
   Added unit tests to `amber/src/test/python/core/models/test_tuple.py`. 
   
   Results:
   
   ```
   # Python unit tests
   pytest src/test/python/core/models/test_tuple.py -q      ->  84 passed
   ruff check / ruff format --check                          ->  clean
   
   # Backend suite
   sbt scalafmtCheckAll                                      ->  exit 0
   sbt "scalafixAll --check"                                 ->  exit 0
   sbt test                                                ->  1717 passed, 0 
failed
   ```
   
   Adversarial check: reverting `cast_to_schema()` to the pre-fix version turns 
exactly the coercion cases red while the guard cases stay green; restoring the 
fix returns to all-green. Every pass-case asserts the concrete Python type, so 
a test cannot pass without the fix.
   
   Also reproduced end-to-end in the platform: `CSV File Scan` → `Python UDF` 
(`yield {"total_age": table["age"].sum()}` / `{"has_senior": (table["age"] > 
60).any()}`) crashed with `Unmatched type ... numpy.int64` / `numpy.bool` 
before the fix and runs correctly after.
   
   ### Was this PR authored or co-authored using generative AI tooling?
   
   Co-authored 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]

Reply via email to