Repository navigation
Add a temporal benchmark shape derived from the snapshot timestamp (GH-1287) - #1290
Conversation
…H-1287) The existing shapes keep "timestamp" as a bigint, so no benchmark case converts a temporal value. The temporal shape adds timestamp(3), date, timestamp(3) with time zone (UTC, a zone name, an offset), and time(3) columns derived from it to the flat projection. UNLOAD and CTAS reads project only the timestamp(3) and date columns, because Athena's Hive writer rejects time and with time zone types. The shape covers every family in the single-query suite. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…H-1287) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…H-1287) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
| TEMPORAL_COLUMNS = ( | ||
| f"{PARQUET_TEMPORAL_COLUMNS}, " | ||
| f"from_unixtime({_SECONDS}, 'UTC') AS event_time_utc, " | ||
| f"from_unixtime({_SECONDS}, 'Asia/Tokyo') AS event_time_zone, " |
There was a problem hiding this comment.
Self-review round one (behavior and implementation), base 7b2a084, initial head 1bf7f02, repaired head 7e6349b.
Covered: select_sql() and its callers (runner trial payloads, prepare_fixtures()), matrix() for every suite, the case/job IDs, the docs, and the new tests. Passes: my own read, then /code-review (high), then /simplify (four angles).
Result: FINDINGS, repaired.
- The zone-name column used
America/New_York. Athena writes zone-name values without an offset, and PyAthena raisesDataErrorfor an ambiguous local time. Checked on Athena:from_unixtime(1793511000, 'America/New_York')givesDataError ... '2026-11-01 01:30:00.000 America/New_York' is ambiguous. Any snapshot that includes a fall-back hour would turn every temporal CSV case into a failure. Repaired in 64a8887: the column now usesAsia/Tokyo, which has no DST. README and DATASET.md were updated too.
| }.get(shape) | ||
| if columns is None: | ||
| raise ValueError(f"Unknown shape: {shape}") | ||
| if transport not in {"csv", "unload", "ctas"}: |
There was a problem hiding this comment.
Round one, findings 2-3 (repaired):
select_sql()treated any transport outside{unload, ctas}as CSV, so a misspelled transport would read the full temporal projection. Repaired in 64a8887: an unknown transport raisesValueError. The test is intest_temporal_projection_of_parquet_reads_has_no_time_or_time_zone_types.- Simplifications from my own pass and
/simplify, in 0a96670 and 7e6349b: the shape lookup now runs before the Parquet override, which drops thestr | Noneannotation. After validation, the override checkstransport != "csv". Thematrix()docstring no longer repeats the projection rule fromselect_sql().
Deferred, with reasons:
- Precision 6 for the CSV columns: Benchmark the temporal type conversion changes of 4.2.0 #1287 specifies
timestamp(3), the precision of Hive tables. - One table for both Parquet-incompatible mechanisms (json marked unsupported vs temporal narrowed):
jsonwithout its column would repeatflat, while the narrowed temporal projection still hastimestamp(3)anddate. Unifying them would be an unapproved restructuring. - A shared
TRANSPORTSconstant: the transport literals are also repeated in existing code outside this diff (__main__.py:100,runner.py:557,cases.py). - CSV vs UNLOAD reading different column sets in the temporal shape: documented in README; the report already says to compare cases with the same transport.
| ) | ||
|
|
||
|
|
||
| def test_temporal_trials_query_the_projection_of_their_transport(monkeypatch, tmp_path, run_stubs): |
There was a problem hiding this comment.
Round one, test coverage: test names, mutation checks, and validation results.
Test names: renamed in 64a8887 from ..._query_no_time_zone_columns, which promised more than it checked. This test covers the wiring of run(). The exact Parquet projection is asserted in test_config.py.
Mutation checks on 1bf7f02:
- With the temporal branch of
select_sql()disabled,test_temporal_projection_...fails. - With the runner passing
"csv"instead ofcase.transport, this test fails.
Validation at 7e6349b:
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
| The nested workload preserves those structures. | ||
| The json workload adds `CAST(details AS JSON) AS details_json` to the flat projection; it covers native pandas and Wrangler reads in the single-query suite, with their UNLOAD and CTAS reads marked unsupported, because Parquet cannot hold the `json` type. | ||
| The temporal workload adds columns derived from `"timestamp"` with `from_unixtime()` to the flat projection: `event_time` (`timestamp(3)`), `event_date` (`date`), `event_time_utc`, `event_time_zone`, and `event_time_offset` (`timestamp(3) with time zone` in `UTC`, `Asia/Tokyo`, and `+09:00`), and `event_clock` (`time(3)`). | ||
| It covers every family in the single-query suite; its UNLOAD and CTAS reads add only `event_time` and `event_date`, because UNLOAD and CTAS cannot write `time` or `with time zone` types. |
There was a problem hiding this comment.
Self-review round two (claims, callers, operations), base 7b2a084, initial head 7e6349b, repaired head 998a3b6.
Claims checked: the PR body, README, DATASET.md, the comments and docstrings in config.py and cases.py, and the commit messages.
Result: FINDINGS, repaired.
- README and DATASET.md said that Athena cannot write
timeorwith time zonetypes to Parquet. The evidence covers only UNLOAD and CTAS (NOT_SUPPORTED: Unsupported Hive type); Iceberg Parquet is a separate path that I did not check. Repaired in 998a3b6: the wording now names UNLOAD and CTAS. - The PR body still named
America/New_York, tested commit 1bf7f02, and the old test name, and it left out theValueErrorfor an unknown transport. Repaired in the PR description.
| # through Hive, which has no time or with time zone types, so their reads project | ||
| # the timestamp and date columns only. The zone has no daylight saving time, whose | ||
| # ambiguous local times PyAthena rejects. | ||
| _SECONDS = '"timestamp" / 1e6' |
There was a problem hiding this comment.
Round two, evidence for the claims:
Rerun on Athena after the zone change (two-row VALUES queries, test work group, probe objects removed):
from_unixtime(double)returnstimestamp(3).from_unixtime(double, zone)returnstimestamp(3) with time zone.- UNLOAD and CTAS accept
event_timeandevent_dateand reject the other four columns. - All six columns, with
Asia/Tokyo, read without errors with Cursor, PandasCursor, ArrowCursor, PolarsCursor, and Wrangler CSV. - PandasCursor, ArrowCursor, and PolarsCursor read UNLOAD results of the Parquet projection.
Existing callers: the signature change of select_sql() reaches only runner.run() and aws.prepare_fixtures(), and both pass the transport. Queued fleet jobs carry CLI arguments, not SQL, and workers run the stack's checked-out commit.
Operator view: the temporal columns are computed from "timestamp", which the flat projection already reads, so a query scans no extra columns of the snapshot. The shape adds cases only when --shape temporal is selected; plan shows 138 cases at small, the same count as flat.
Evidence: the transport validation was mutation-checked (with it removed, test_temporal_projection_... fails).
Limits:
- No
prepareorrunagainst a benchmark stack; that run belongs to Run the combined benchmark before the 4.2.0 release #1288. - The benchmark environment resolves Polars 1.44.2 on Python 3.12, so the combined run would not measure the Polars 2.0 UNLOAD path (related to Read and write timestamps at Athena's precision for each path #1289 item 1). This is outside this PR and will be raised with the maintainer.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
| def test_temporal_shape_covers_every_flat_case_in_the_single_query_suite(): | ||
| cases = matrix(Settings(), "single", "temporal") | ||
| # UNLOAD and CTAS read a Parquet projection instead of being unsupported. | ||
| assert [replace(c, shape="flat") for c in cases] == matrix(Settings(), "single", "flat") |
There was a problem hiding this comment.
Independent review (relayed), static only.
Reviewer: Codex CLI 0.163.0, model gpt-6-astra, reasoning effort max, codex exec --sandbox read-only, session 01a14f34-7a9c-7771-9350-35a3ae161e7b. Base 7b2a084, head 998a3b6, on a detached snapshot (unchanged afterwards). The reviewer got the literal diff, the conventions, and the testing guide. It got no PR text, commit messages, or prior findings. Instructions: no edits, builds, tests, or network access.
Covered: both select_sql() callers, fixture preparation, and transport validation. All four suites; CLI plan/run/jobs; fleet filtering and case identity. PyAthena row/native paths, Wrangler CSV/CTAS/UNLOAD, SQLAlchemy, failure propagation, and reporting. Changed tests against existing coverage and docs/testing.md; README/DATASET accuracy; imports, docstrings, and structural scope.
Result: FINDINGS (1). No runtime defect was identified.
- P3 — The matrix test masks an incorrect result shape. This line replaces every returned case's shape with
"flat"before comparing. A regression that returns flat cases formatrix(Settings(), "single", "temporal")would therefore pass, althoughrun()would select flat SQL and measure no temporal conversion. The new runner test constructs temporal cases directly, so it would also miss that regression.
There was a problem hiding this comment.
Repaired in 1086ef7: the test now compares matrix(Settings(), "single", "temporal") with the flat cases converted to shape="temporal", so the actual shape stays in the comparison.
Validation:
- Mutation check: with
matrix()returning flat cases for the temporal shape, this test now fails. just benchmark lint: passed.just benchmark test: 251 passed, 1 skipped.
Self-review of the repair:
- Round one: behavior and tests. It changes only the assertion. The contract (every flat case, UNLOAD and CTAS included, none unsupported) is unchanged.
- Round two: claims. The PR description's tested commit and mutation checks were updated. No docs change.
Independent follow-up: Codex CLI 0.163.0, gpt-6-astra, effort max, read-only, session 01a14f39-7cc6-7903-aa3f-576bc5ab161b, on the detached snapshot of 1086ef7 and the diff 998a3b6..1086ef7. Result: CLEAN. "The actual temporal cases remain untouched, so returning flat shapes now fails. Full Case equality preserves comparison of every flat case and option, including UNLOAD, CTAS, and unsupported=None." Static inspection only.
WHAT
Adds a
temporalshape to the benchmark harness (benchmarks/pyathena_bench). It adds the following columns, derived from the snapshot's bigint"timestamp"(epoch microseconds), to the flat projection:event_timefrom_unixtime("timestamp" / 1e6)timestamp(3)event_dateCAST(... AS date)dateevent_time_utcfrom_unixtime("timestamp" / 1e6, 'UTC')timestamp(3) with time zoneevent_time_zonefrom_unixtime("timestamp" / 1e6, 'Asia/Tokyo')timestamp(3) with time zoneevent_time_offsetfrom_unixtime("timestamp" / 1e6, '+09:00')timestamp(3) with time zoneevent_clockCAST(... AS time(3))time(3)select_sql()now takes the transport and raisesValueErrorfor an unknown transport. For thetemporalshape, UNLOAD and CTAS reads project onlyevent_timeandevent_date, because UNLOAD and CTAS cannot write the other types. The other shapes return the same SQL for every transport. The runner andprepare_fixtures()pass the case's transport.matrix()gives thetemporalshape the same cases asflatin the single-query suite. UNLOAD and CTAS stay supported, through the Parquet projection. Likejson, the shape has no cases in the concurrent and initialization suites.Asia/Tokyo, a zone without daylight saving time. A zone name with an ambiguous fall-back hour, such asAmerica/New_Yorkon 2026-11-01, makes PyAthena raiseDataError(checked on Athena), which would turn the CSV cases of a snapshot from such a day into failures.runcommand.WHY
Part of #1287 (harness change; the measurement belongs to the combined run of #1288). The existing
flat,nested, andjsonshapes keep"timestamp"as abigint, so no case measures the temporal conversions that changed in 4.2.0 (#1233, #1234, #1236, #1273, #1277, #1224). The combined run of #1288 needs this shape on the commit planned for 4.2.0. The shape needs no new input data.TEST
Tested commit: 1086ef7
just lint,just benchmark lint,just docs lint: passed.just benchmark test: 251 passed, 1 skipped.test_temporal_projection_of_parquet_reads_has_no_time_or_time_zone_types: the CSV, UNLOAD, and CTAS SQL of the shape.test_temporal_shape_covers_every_flat_case_in_the_single_query_suite.test_temporal_trials_query_the_projection_of_their_transport: the SQL in the trial payloads ofrun().select_sql()disabled, the projection test fails. With the transport validation removed, the same test fails. With the runner passing"csv"instead ofcase.transport, the runner test fails. Withmatrix()returning flat cases for the temporal shape, the matrix test fails.plan --suite single --scale small --shape temporal: 138 cases, the same count asflat.jobs --shape temporalproduced job IDs such assingle-small-temporal-pandas-sync-unload-native.VALUESqueries (test work group, objects removed afterwards):from_unixtime(double)returnstimestamp(3), andfrom_unixtime(double, zone)returnstimestamp(3) with time zone.timestamp(3)anddate. They fail forwith time zoneandtime(3)withNOT_SUPPORTED: Unsupported Hive type.Asia/Tokyo) read without errors with Cursor, PandasCursor, ArrowCursor, PolarsCursor, and Wrangler CSV. UNLOAD reads ofevent_timeandevent_datesucceeded with PandasCursor, ArrowCursor, and PolarsCursor.Not run: the harness against a benchmark stack (
prepare/run), which needs the CloudFormation stack and belongs to the combined run of #1288. The Athena checks above ran the shape's column expressions directly, not the harness's full queries over a snapshot.🤖 Generated with Claude Code