Repository navigation
feat: add dtype_backend to result loading - #1128
binaryaaron wants to merge 5 commits into
Conversation
|
Fern preview: https://nvidia-preview-pr-1128.docs.buildwithfern.com/nemo/datadesigner
|
[Medium impact] The PR appears safe to merge; no actionable correctness issues were found. SummaryAdds
No actionable new issues were found. No previous review threads were supplied.
|
svcnvidia-nemo-ci
left a comment
There was a problem hiding this comment.
No qualifying findings.
I reviewed all seven changed files against the base and traced the result-loading path through engine storage and both native and JSON-encoded readers. The public API preserves the Arrow default. Explicit backend choices reach file, directory, and schema-unification fallback reads, while decoded JSON columns retain object dtype.
The inspected regressions cover public loading through real storage, native nested numeric promotion, fallback conversion, and file/directory consistency. I couldn't execute tests in this read-only environment; this approval is based on source and test inspection.
Note: formal approval is not available for this request, so this review is posted as a comment only.
Review generated by codex. This was a full review. Request a full review with /review reset=true.
|
Thanks for putting this together, @binaryaaron! SummaryPR #1128 adds dtype_backend selection to DatasetCreationResults.load_dataset and forwards it through artifact loading while preserving the Arrow default. Two P2 issues affect native-column dtypes when loading JSON-encoded artifacts. Could you share the concrete downstream use case driving this API addition? Which consumer needs FindingsWarnings — Worth addressing
What Looks Good
Residual RiskValidation: 271 targeted tests passed on pandas 3.0.5 / PyArrow 24.0.0, and lint/format checks passed for all seven changed files. The string-inference and categorical failures were reproduced through DatasetCreationResults.load_dataset; the fixed-offset timestamp concatenation failure was also reproduced. The full suite and pandas 2.3.3 matrix reported by the author were not independently rerun. VerdictNeeds changes — align pandas conversion semantics and preserve categorical dtype across encoded batches. This review was generated by an AI assistant. |
@nabinchha, I recommend fixing the reader here and reviewing the Arrow update independently. Both findings reproduce. The timezone mismatch specifically reproduces with pandas 3 / Arrow 24 when The tested options are:
Proposed reader fix: validate each fragment's JSON contract, read native columns together through public The shorter alternatives failed concrete cases: reading everything through pandas before JSON decoding rounded a native nested integer from The prototype changes three files (+91/−61 relative to this head), with 9 net production lines added and no new test functions. Existing public-load cases gain two batches with differing categories, fixed-offset timestamps, and disabled string inference, comparing native columns against pandas. These expose failures on this head and pass in all six combinations of pandas 2.3.3/3.0.5 × Arrow 24.0.0/25.0.0/26.0.1. The broader matrix passed 468 checks per combination, including 60 exploratory probes kept outside the proposed patch. Independent dependency proposal: widen all three constraints to On motivation: this originated in Anonymizer's result/export integration, but this API does not fix its nested-Arrow metadata export failure. The intended benefit is choosing pandas' read semantics at the artifact boundary instead of manually reading files or casting afterward. A separate consumer requiring |
| if field.name not in schema.names: | ||
| schema = schema.append(field) | ||
| frames.append(decode_storage_table(fragment.to_table(schema=schema))) | ||
| frames.append(decode_storage_table(fragment.to_table(schema=schema), dtype_backend=dtype_backend)) |
There was a problem hiding this comment.
It looks like numpy_nullable can lose its nullable dtype here on pandas 3. With batches containing x=[1] and x=[None], I get an object column when a JSON-encoded sibling is present, versus Int64 without it. Would resolving native column types before converting the fragments help? An all-null shard might be a useful regression case.
There was a problem hiding this comment.
agent (
review-pr): Fixed in 508dcfc6: native fragment schemas are resolved before conversion, so an all-null shard no longer turns a nullable integer into object dtype. The existing public-load test now writes two batches, including this null-shard case, and compares the native columns with pandas' reader. Checked on pandas 2.3.3 and 3.0.5.
| elif dtype_backend == "numpy_nullable": | ||
| frame = table.to_pandas(types_mapper=_get_numpy_nullable_type_mapping().get) | ||
| elif dtype_backend is None: | ||
| frame = table.to_pandas() |
There was a problem hiding this comment.
I noticed a small difference from the native reader on pandas 3 with future.infer_string=False: dtype_backend=None gives object strings with None for native files, but str columns with NaN for JSON-annotated files. This seems to come from skipping pandas’ post-conversion cleanup. It might be worth aligning these so a JSON-encoded sibling doesn’t affect unrelated string columns.
There was a problem hiding this comment.
agent (
review-pr): Fixed in 508dcfc6: both readers now share native conversion, withNoneandnumpy_nullabledelegated to publicpd.read_parquet. The public-load regression usesfuture.infer_string=Falseand null strings and checks values and dtypes against pandas, alongside fixed-offset timestamps and categories.
| A pandas DataFrame containing the full generated dataset. | ||
| """ | ||
| return self.artifact_storage.load_dataset() | ||
| return self.artifact_storage.load_dataset(dtype_backend=dtype_backend) |
There was a problem hiding this comment.
Maybe we could validate dtype_backend at this boundary? At the moment, an invalid value with missing artifacts produces FileNotFoundError before reaching argument validation. Checking it here would give callers a clearer error, and a small public-API test could cover that.
There was a problem hiding this comment.
agent (
review-pr): Implemented in 508dcfc6:read_parquet_datasetvalidates the backend before artifact access, so the public API raisesValueErroreven when artifacts are missing. The previous internal validation test was moved toload_datasetand covers both artifact-present and artifact-missing cases.
|
@binaryaaron after your comment during our sync, I looked more closely at how this PR relates to #1142. Indeed, they’re related, but the fix in #1142 looked fine to merge separately. For this PR, I think the reader approach you proposed is the way to go: read native columns together through pandas, then restore JSON columns from the original fragments. That should also cover the null-shard and string-conversion cases I commented on yesterday. Now that #1142 is merged, maybe we can rebase this and make that reader change while keeping its regression coverage? |
DatasetCreationResults.load_dataset() always read parquet with
dtype_backend="pyarrow", so nested columns came back as ArrowDtype.
Add a keyword-only dtype_backend ("pyarrow" default, "numpy_nullable",
or None) threaded through ArtifactStorage.load_dataset() and
read_parquet_dataset(), including the schema-unification and encoded
JSON storage branches. None omits the pandas option, so pandas applies
its default conversion (nested columns as object).
The default is unchanged. CompositeWorkflow.load_dataset does not yet
expose the option.
🤖 Generated with Claude Code
Co-Authored-By: Claude <noreply@anthropic.com>
Signed-off-by: Aaron Gonzales <aagonzales@nvidia.com>
Document that dtype_backend=None follows pandas conversion and stored metadata. Encoded JSON columns retain object dtype for every backend; loading does not repair incompatible persisted Arrow dtype metadata. Extend the public result-loading regression through a Parquet write and pandas default read for None and numpy_nullable. Preserve the existing pyarrow default. Signed-off-by: Aaron Gonzales <aagonzales@nvidia.com>
Use an explicit typed nullable dtype mapping in encoded storage. Consolidate public coverage around real result loading for each backend and remove redundant pandas export/read-back coverage. Preserve the Arrow default and decoded JSON values. Export compatibility and nested-container normalization remain outside the loading contract. Signed-off-by: Aaron Gonzales <aagonzales@nvidia.com>
Exercise native and JSON-encoded backend selection through real result storage, and reuse the numeric-promotion regression across backends. Keep focused fallback and invalid-input checks while removing duplicate storage/reader tests and their setup helpers. Compare dtype objects directly so the tests express conversion semantics across supported pandas versions. Signed-off-by: Aaron Gonzales <aagonzales@nvidia.com>
Preserve Arrow buffers through the documented conversion hook and reuse pandas public conversion for the non-Arrow backends. Resolve native fragment schemas before conversion while restoring JSON values from their original fragments. Validate backend choices before artifact access and strengthen the existing public and nested-array regressions without adding test functions to the previous PR. Signed-off-by: Aaron Gonzales <aagonzales@nvidia.com>
0d3efdb to
508dcfc
Compare
@nabinchha @andreatnvidia, the branch now builds on updated
The earlier prototype in my proposal is superseded: checking it against #1142 exposed metadata/index regressions, which this implementation covers. The final diff against updated Validation: 5,256 passed, 3 skipped in Dependencies remain unchanged; the Arrow upgrade remains a separate option. The API motivation also remains as previously qualified: choosing pandas conversion at the load boundary is the benefit, but a separate consumer requiring |
andreatnvidia
left a comment
There was a problem hiding this comment.
@binaryaaron thanks for the update, this addresses the points from the earlier review. I ran another pass, including live generation and export workflows, and found two remaining edge cases: a unified read can fail on large nested integers without reaching the per-fragment fallback, and recombining native and JSON columns drops unrelated DataFrame attrs. I’d get the fallback case fixed before merging; the attrs issue seems less urgent.
| ], | ||
| ignore_index=True, | ||
| ) | ||
| return read_native_parquet( |
There was a problem hiding this comment.
There seems to be a fallback case missing here. With a JSON-encoded column alongside a native struct containing 9007199254740993 in one shard and 0.5 in another, the default load_dataset() works on the base but now raises ArrowInvalid. Schema unification succeeds; the later read fails because the integer cannot safely become a double. Could the per-fragment fallback also handle that read-time conversion failure?
| [decode_storage_table(fragment.to_table(columns=list(plan.columns))) for fragment in fragments], | ||
| ignore_index=True, | ||
| ) | ||
| frame = lazy.pd.concat([native.reset_index(drop=True), protected], axis=1) |
There was a problem hiding this comment.
I noticed that this concat drops unrelated DataFrame attributes. For example, attrs={'external': {'units': 'USD'}} survives an encoded round trip on the base, but disappears here. The protected frame has the JSON storage attribute added, so its attrs differ from the native frame’s. Maybe we could carry forward the attributes retained by the protected-fragment concat?
📋 Summary
Add keyword-only
dtype_backendselection toDatasetCreationResults.load_dataset()while preserving the Arrow default and decoded JSON values. Native columns now have consistent conversion across ordinary and JSON-encoded artifacts, including multi-batch datasets.Rebased onto
mainafter #1142 merged.🔗 Related Issue
Builds on merged #1142. No separate dtype-selection issue is linked.
🔄 Changes
"pyarrow"(default),"numpy_nullable", andNone; validate invalid choices before artifact access.pd.read_parquet, retaining its string-inference and timezone behavior.🧪 Testing
make test: 5,256 passed, 3 skipped on Python 3.14 / pandas 3.0.5 / Arrow 24.0.0.pytzpresent.make check-all, complexity checks, diff checks, and normal commit hooks.Reviewer Notes
Dependencies and the serialization format are unchanged. This API selects load-time representation; it does not promise to repair incompatible exported pandas metadata or normalize nested containers. The choices follow pandas' API; a separate consumer requiring
numpy_nullablehas not been established.Description updated with AI assistance.