Skip to content

Centralize shared execute() kwargs into an ExecuteOptions dataclass#733

Draft
laughingman7743 wants to merge 4 commits into
masterfrom
feature/execute-options
Draft

Centralize shared execute() kwargs into an ExecuteOptions dataclass#733
laughingman7743 wants to merge 4 commits into
masterfrom
feature/execute-options

Conversation

@laughingman7743

@laughingman7743 laughingman7743 commented Jul 6, 2026

Copy link
Copy Markdown
Member

WHAT

Extracts the execute() arguments shared by all cursor implementations into a frozen ExecuteOptions dataclass (pyathena/options.py) and refactors the internal plumbing to pass it around instead of nine individual kwargs.

  • BaseCursor._execute() / AioBaseCursor._execute() now take (operation, parameters, options). This is a private-API signature change; third-party code calling _execute() with the old kwargs needs updating.
  • Every cursor's execute() keeps its existing keyword arguments unchanged (fully backward compatible) and additionally accepts a keyword-only options: ExecuteOptions | None parameter. When both are given, individual kwargs take precedence over options fields; None kwargs are treated as "not specified" and do not reset options fields.
  • ExecuteOptions.resolve() is the single home for the options-plus-kwargs merge used by all 15 execute() implementations, and BaseCursor._call_on_start_query_execution() centralizes the callback invocation previously copy-pasted per cursor.
  • The cache_size / cache_expiration_time signature defaults change from 0 to None; the effective default of 0 now lives on the dataclass, so behavior is identical.
  • The aio pandas/arrow/polars/s3fs cursors gain the explicit result_set_type_hints argument they were missing (previously only reachable via **kwargs forwarding).
  • The aio cursors now support on_start_query_execution (connection-level, execute-level kwarg, and via options). Unlike AsyncCursor, they wait for query completion, so the early-query-ID callback is meaningful there. AsyncCursor-based cursors continue to ignore it as documented.
  • ExecuteOptions is exported from the package root (from pyathena import ExecuteOptions) and documented in the usage guide and API reference.

Tests:

  • tests/pyathena/test_options.py: unit tests for defaults, immutability, and merge()/resolve() precedence (including falsy values like False/0 overriding).
  • tests/pyathena/test_cursor.py / tests/pyathena/aio/test_cursor.py: integration tests running queries via options=ExecuteOptions(...), verifying kwargs-over-options precedence and the new aio callback support end to end.
  • Full tests/pyathena/test_cursor.py (105 passed), async cursor suite, all callback tests (14 passed), and per-cursor smoke tests (pandas/arrow/polars/s3fs, sync/async/aio) pass against real Athena.

WHY

Closes #691.

Each new shared execute() parameter (e.g. result_set_type_hints in #690) currently requires editing 11+ cursor files with identical boilerplate. Centralizing the shared kwargs in one dataclass means a future parameter is added in 1-2 files (the dataclass plus the internal reference), gives all cursor types the same defaults/merge semantics, and provides a single documentation source for the shared arguments — while keeping every existing call site working unchanged.

🤖 Generated with Claude Code

laughingman7743 and others added 4 commits July 6, 2026 23:14
Extract the execution arguments shared by all cursor implementations
(work_group, s3_staging_dir, cache_size, cache_expiration_time,
result_reuse_enable, result_reuse_minutes, paramstyle,
on_start_query_execution, result_set_type_hints) into a frozen
ExecuteOptions dataclass in pyathena/options.py.

- BaseCursor._execute() and AioBaseCursor._execute() now take a single
  ExecuteOptions instead of nine individual kwargs
- Every cursor's execute() keeps its existing keyword arguments for
  backward compatibility and additionally accepts a keyword-only
  options parameter; individual kwargs take precedence over options
- Adding a new shared execute() argument now only requires changes to
  the dataclass and the internals, not all cursor signatures
- Add the explicit result_set_type_hints argument to the aio
  pandas/arrow/polars/s3fs cursors, which previously relied on kwargs
  forwarding, for consistency with the other cursors
- Export ExecuteOptions from the pyathena package root and document it
  in the usage guide and API reference

Closes #691

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- Simplify ExecuteOptions.merge() to rely on dataclasses.replace() for
  unknown-field validation and remove the unused logging boilerplate
- Type cache_size/cache_expiration_time as plain int with default 0 and
  drop the duplicated None coercion in both _execute implementations
- Add ExecuteOptions.resolve() and use it in all execute() methods
  instead of repeating the default-construction-and-merge expression
- Invoke on_start_query_execution callbacks in the aio cursors, which
  wait for query completion like the synchronous cursors, and add the
  explicit on_start_query_execution argument to their execute() methods
- Add missing execute() docstrings to AsyncPandasCursor and
  AsyncArrowCursor
- Clarify cache_size/cache_expiration_time interplay in the
  ExecuteOptions docstring, scope the usage guide section to SQL
  cursors, and document that None keyword arguments do not reset
  options fields

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…eview

- Extract the connection-level and execute-level on_start_query_execution
  invocation, previously repeated in 10 cursor execute() methods, into
  BaseCursor._call_on_start_query_execution
- Use ExecuteOptions.resolve() for the None fallback in both _execute
  implementations instead of an inline conditional

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Refactor shared execute() kwargs handling across cursor implementations

1 participant