HyukjinKwon commented on PR #54:
URL:
https://github.com/apache/spark-connect-rust/pull/54#issuecomment-5419042912
<!-- ai-code-review -->
## Re-review at `9a34c8a` (after the fixes)
Took a fresh, thorough pass over the new head — verified every fix against
the code (again manually; the `spark-dev page` harness still can't read its
`/tmp` scratch on macOS). **All three must-fix items from the first pass are
correctly and completely resolved.** Details, then two small new items this
pass surfaced.
### Verified fixed ✅
- **#1 TIMESTAMP `createDataFrame` regression** — `build_arrow_array` now
threads the target field type and applies `.with_timezone("UTC")` for LTZ /
none for NTZ (session.rs:843-855), so the array type matches the `Timestamp(us,
Some("UTC"))` schema. Correct.
- **#2 gate scores `ok` on a no-summary run** — `run_ours` now records
`counts["rc"]` and a shared `is_bad()` gates on pytest's exit code across the
retry loop, the failure decision, and the drift check; `rc=5` (no tests
collected) is treated as ok, and a no-summary nonzero exit is surfaced as
`rc=N`. A broken extension/plugin load now fails the gate. Correct.
- **#3 plural `"errors"` regex** — now `(\d+) errors?\b`, and subsumed by
the returncode check anyway. Correct.
- **#4 `approxQuantile`** returns `list[float]` (collects the inner quantile
list, `[]` on empty, no panic). **#5 `persist(level)`** honors the StorageLevel
(default → `MEMORY_AND_DISK_DESER`). **#6 `repartition("col")`** column-first
form works and `num_partitions <= 0` serializes as unset (plan.rs:665). **#8
`hint(name, 3)`** accepts ints and sends an `Integer`/int32 literal
(plan.rs:748). **#10 `coerce_value`** widens Long/Integer → Float. All correct.
- The new production fixes also check out: **`selectExpr`** now uses
`functions::expr` (server-parsed SQL, one expr per string), **`toJSON`**
projects `to_json(struct(*))` server-side, and **`DataType.simpleString`**
returns `"string"` for the default/UTF8_BINARY collation. Correct.
### New this pass
**A. LOW — the option-coercion fix (#7) missed `DataFrameWriterV2`.**
`coerce_option_value` (None → unset, bool → lowercase) was wired into the
reader, the V1 writer, streaming reader/writer, and `conf.set` — but
`crates/pyspark-rs/src/dataframe.rs:1300` `PyDataFrameWriterV2::option(value:
&str)` and `:1312` `options` still use raw `v.str()`. So
`df.writeTo("t").options(mergeSchema=None)` inserts the literal `"None"` and
`options(overwrite=True)` sends `"True"`, same bug class as #7. Uncommon path
(V2 writer), but it's an incomplete fix.
**B. MEDIUM (test infra) — the new `e2e_*` tests don't run in CI, and the
golden→behavioral swap dropped a few server-free serialization guards.**
- `e2e_functions.rs` / `e2e_columns.rs` / `e2e_dataframe.rs` and the
server-gated tests in `e2e_coverage.rs` all self-gate on `should_run()` = `env
SPARK_REMOTE is_ok()`. **No workflow sets `SPARK_REMOTE`** — CI uses
`SPARK_CONNECT_TESTING_REMOTE` for the Python parity gate, and the `cargo test`
invocations (`rust.yml`, the `rust-checks` job) run with no server. So these
tests return immediately and assert nothing in CI; their value assertions
(which are genuinely good — `md5("abc")=…`, `element_at(arr,1)=3`, etc.) only
run locally. (`types_behavior.rs` is *not* gated and does run in CI — good.)
- The swap deleted `plan_coverage_golden.rs::every_plan_builder_serializes`,
a server-free completeness net. Most of its surface survives
(`functions_golden.rs` 440 cases, `plans_golden.rs` 46, and `grouping_sets` is
still guarded by `plan_arg_regression_golden.rs:443`), but I couldn't find a
surviving CI-running serialization test for the `RightOuter` / `FullOuter` /
`LeftSemi` / `LeftAnti` join variants or `local_relation` /
`cached_remote_relation` — their only remaining coverage is the CI-skipped
`e2e_*` tests (joins are still exercised indirectly by the live Python parity
gate).
Neither A nor B is a functional/production bug. Two cheap closes for B: set
`SPARK_REMOTE=sc://localhost:15002` in the `connect-parity` job and run `cargo
test` there against the already-running server, and/or keep a server-free
serialization guard for the dropped plan builders.
### Out of scope (pre-existing, untouched by this PR)
`functions::cast(_col, to_col) -> to_col` (functions.rs:96) ignores its
input column and returns the target as-is — a no-op that `audit_no_stubs.sh`
doesn't catch (it compiles and returns a value). Introduced in the merged core
commit, not this PR, and there's no `pyspark.sql.functions.cast` in reference
PySpark for it to mirror — worth a separate follow-up.
---
**Verdict:** the blockers are resolved; what remains is one minor fidelity
gap (A) and test-infra hygiene (B). Good to merge once A/B are addressed or
consciously deferred.
This review was written by Isaac.
--
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]
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]