PyAthena 3.31.0__tar.gz → 3.32.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (88) hide show
  1. {pyathena-3.31.0 → pyathena-3.32.0}/PKG-INFO +1 -1
  2. {pyathena-3.31.0 → pyathena-3.32.0}/pyathena/_version.py +2 -2
  3. {pyathena-3.31.0 → pyathena-3.32.0}/pyathena/aio/common.py +2 -0
  4. {pyathena-3.31.0 → pyathena-3.32.0}/pyathena/aio/spark/cursor.py +2 -0
  5. {pyathena-3.31.0 → pyathena-3.32.0}/pyathena/arrow/cursor.py +0 -3
  6. {pyathena-3.31.0 → pyathena-3.32.0}/pyathena/common.py +18 -0
  7. {pyathena-3.31.0 → pyathena-3.32.0}/pyathena/connection.py +10 -1
  8. {pyathena-3.31.0 → pyathena-3.32.0}/pyathena/cursor.py +0 -2
  9. {pyathena-3.31.0 → pyathena-3.32.0}/pyathena/filesystem/s3.py +9 -2
  10. {pyathena-3.31.0 → pyathena-3.32.0}/pyathena/pandas/cursor.py +0 -3
  11. {pyathena-3.31.0 → pyathena-3.32.0}/pyathena/polars/cursor.py +0 -3
  12. {pyathena-3.31.0 → pyathena-3.32.0}/pyathena/s3fs/cursor.py +0 -3
  13. {pyathena-3.31.0 → pyathena-3.32.0}/pyathena/spark/common.py +2 -0
  14. {pyathena-3.31.0 → pyathena-3.32.0}/.gitignore +0 -0
  15. {pyathena-3.31.0 → pyathena-3.32.0}/LICENSE +0 -0
  16. {pyathena-3.31.0 → pyathena-3.32.0}/README.md +0 -0
  17. {pyathena-3.31.0 → pyathena-3.32.0}/pyathena/__init__.py +0 -0
  18. {pyathena-3.31.0 → pyathena-3.32.0}/pyathena/aio/__init__.py +0 -0
  19. {pyathena-3.31.0 → pyathena-3.32.0}/pyathena/aio/arrow/__init__.py +0 -0
  20. {pyathena-3.31.0 → pyathena-3.32.0}/pyathena/aio/arrow/cursor.py +0 -0
  21. {pyathena-3.31.0 → pyathena-3.32.0}/pyathena/aio/connection.py +0 -0
  22. {pyathena-3.31.0 → pyathena-3.32.0}/pyathena/aio/cursor.py +0 -0
  23. {pyathena-3.31.0 → pyathena-3.32.0}/pyathena/aio/pandas/__init__.py +0 -0
  24. {pyathena-3.31.0 → pyathena-3.32.0}/pyathena/aio/pandas/cursor.py +0 -0
  25. {pyathena-3.31.0 → pyathena-3.32.0}/pyathena/aio/polars/__init__.py +0 -0
  26. {pyathena-3.31.0 → pyathena-3.32.0}/pyathena/aio/polars/cursor.py +0 -0
  27. {pyathena-3.31.0 → pyathena-3.32.0}/pyathena/aio/result_set.py +0 -0
  28. {pyathena-3.31.0 → pyathena-3.32.0}/pyathena/aio/s3fs/__init__.py +0 -0
  29. {pyathena-3.31.0 → pyathena-3.32.0}/pyathena/aio/s3fs/cursor.py +0 -0
  30. {pyathena-3.31.0 → pyathena-3.32.0}/pyathena/aio/spark/__init__.py +0 -0
  31. {pyathena-3.31.0 → pyathena-3.32.0}/pyathena/aio/sqlalchemy/__init__.py +0 -0
  32. {pyathena-3.31.0 → pyathena-3.32.0}/pyathena/aio/sqlalchemy/arrow.py +0 -0
  33. {pyathena-3.31.0 → pyathena-3.32.0}/pyathena/aio/sqlalchemy/base.py +0 -0
  34. {pyathena-3.31.0 → pyathena-3.32.0}/pyathena/aio/sqlalchemy/pandas.py +0 -0
  35. {pyathena-3.31.0 → pyathena-3.32.0}/pyathena/aio/sqlalchemy/polars.py +0 -0
  36. {pyathena-3.31.0 → pyathena-3.32.0}/pyathena/aio/sqlalchemy/rest.py +0 -0
  37. {pyathena-3.31.0 → pyathena-3.32.0}/pyathena/aio/sqlalchemy/s3fs.py +0 -0
  38. {pyathena-3.31.0 → pyathena-3.32.0}/pyathena/aio/util.py +0 -0
  39. {pyathena-3.31.0 → pyathena-3.32.0}/pyathena/arrow/__init__.py +0 -0
  40. {pyathena-3.31.0 → pyathena-3.32.0}/pyathena/arrow/async_cursor.py +0 -0
  41. {pyathena-3.31.0 → pyathena-3.32.0}/pyathena/arrow/converter.py +0 -0
  42. {pyathena-3.31.0 → pyathena-3.32.0}/pyathena/arrow/result_set.py +0 -0
  43. {pyathena-3.31.0 → pyathena-3.32.0}/pyathena/arrow/util.py +0 -0
  44. {pyathena-3.31.0 → pyathena-3.32.0}/pyathena/async_cursor.py +0 -0
  45. {pyathena-3.31.0 → pyathena-3.32.0}/pyathena/converter.py +0 -0
  46. {pyathena-3.31.0 → pyathena-3.32.0}/pyathena/error.py +0 -0
  47. {pyathena-3.31.0 → pyathena-3.32.0}/pyathena/filesystem/__init__.py +0 -0
  48. {pyathena-3.31.0 → pyathena-3.32.0}/pyathena/filesystem/s3_async.py +0 -0
  49. {pyathena-3.31.0 → pyathena-3.32.0}/pyathena/filesystem/s3_executor.py +0 -0
  50. {pyathena-3.31.0 → pyathena-3.32.0}/pyathena/filesystem/s3_object.py +0 -0
  51. {pyathena-3.31.0 → pyathena-3.32.0}/pyathena/formatter.py +0 -0
  52. {pyathena-3.31.0 → pyathena-3.32.0}/pyathena/model.py +0 -0
  53. {pyathena-3.31.0 → pyathena-3.32.0}/pyathena/pandas/__init__.py +0 -0
  54. {pyathena-3.31.0 → pyathena-3.32.0}/pyathena/pandas/async_cursor.py +0 -0
  55. {pyathena-3.31.0 → pyathena-3.32.0}/pyathena/pandas/converter.py +0 -0
  56. {pyathena-3.31.0 → pyathena-3.32.0}/pyathena/pandas/result_set.py +0 -0
  57. {pyathena-3.31.0 → pyathena-3.32.0}/pyathena/pandas/util.py +0 -0
  58. {pyathena-3.31.0 → pyathena-3.32.0}/pyathena/parser.py +0 -0
  59. {pyathena-3.31.0 → pyathena-3.32.0}/pyathena/polars/__init__.py +0 -0
  60. {pyathena-3.31.0 → pyathena-3.32.0}/pyathena/polars/async_cursor.py +0 -0
  61. {pyathena-3.31.0 → pyathena-3.32.0}/pyathena/polars/converter.py +0 -0
  62. {pyathena-3.31.0 → pyathena-3.32.0}/pyathena/polars/result_set.py +0 -0
  63. {pyathena-3.31.0 → pyathena-3.32.0}/pyathena/polars/util.py +0 -0
  64. {pyathena-3.31.0 → pyathena-3.32.0}/pyathena/py.typed +0 -0
  65. {pyathena-3.31.0 → pyathena-3.32.0}/pyathena/result_set.py +0 -0
  66. {pyathena-3.31.0 → pyathena-3.32.0}/pyathena/s3fs/__init__.py +0 -0
  67. {pyathena-3.31.0 → pyathena-3.32.0}/pyathena/s3fs/async_cursor.py +0 -0
  68. {pyathena-3.31.0 → pyathena-3.32.0}/pyathena/s3fs/converter.py +0 -0
  69. {pyathena-3.31.0 → pyathena-3.32.0}/pyathena/s3fs/reader.py +0 -0
  70. {pyathena-3.31.0 → pyathena-3.32.0}/pyathena/s3fs/result_set.py +0 -0
  71. {pyathena-3.31.0 → pyathena-3.32.0}/pyathena/spark/__init__.py +0 -0
  72. {pyathena-3.31.0 → pyathena-3.32.0}/pyathena/spark/async_cursor.py +0 -0
  73. {pyathena-3.31.0 → pyathena-3.32.0}/pyathena/spark/cursor.py +0 -0
  74. {pyathena-3.31.0 → pyathena-3.32.0}/pyathena/sqlalchemy/__init__.py +0 -0
  75. {pyathena-3.31.0 → pyathena-3.32.0}/pyathena/sqlalchemy/arrow.py +0 -0
  76. {pyathena-3.31.0 → pyathena-3.32.0}/pyathena/sqlalchemy/base.py +0 -0
  77. {pyathena-3.31.0 → pyathena-3.32.0}/pyathena/sqlalchemy/compiler.py +0 -0
  78. {pyathena-3.31.0 → pyathena-3.32.0}/pyathena/sqlalchemy/constants.py +0 -0
  79. {pyathena-3.31.0 → pyathena-3.32.0}/pyathena/sqlalchemy/pandas.py +0 -0
  80. {pyathena-3.31.0 → pyathena-3.32.0}/pyathena/sqlalchemy/polars.py +0 -0
  81. {pyathena-3.31.0 → pyathena-3.32.0}/pyathena/sqlalchemy/preparer.py +0 -0
  82. {pyathena-3.31.0 → pyathena-3.32.0}/pyathena/sqlalchemy/requirements.py +0 -0
  83. {pyathena-3.31.0 → pyathena-3.32.0}/pyathena/sqlalchemy/rest.py +0 -0
  84. {pyathena-3.31.0 → pyathena-3.32.0}/pyathena/sqlalchemy/s3fs.py +0 -0
  85. {pyathena-3.31.0 → pyathena-3.32.0}/pyathena/sqlalchemy/types.py +0 -0
  86. {pyathena-3.31.0 → pyathena-3.32.0}/pyathena/sqlalchemy/util.py +0 -0
  87. {pyathena-3.31.0 → pyathena-3.32.0}/pyathena/util.py +0 -0
  88. {pyathena-3.31.0 → pyathena-3.32.0}/pyproject.toml +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: PyAthena
3
- Version: 3.31.0
3
+ Version: 3.32.0
4
4
  Summary: Python DB API 2.0 (PEP 249) client for Amazon Athena
5
5
  Project-URL: homepage, https://github.com/pyathena-dev/PyAthena/
6
6
  Project-URL: repository, https://github.com/pyathena-dev/PyAthena/
@@ -18,7 +18,7 @@ version_tuple: tuple[int | str, ...]
18
18
  commit_id: str | None
19
19
  __commit_id__: str | None
20
20
 
21
- __version__ = version = '3.31.0'
22
- __version_tuple__ = version_tuple = (3, 31, 0)
21
+ __version__ = version = '3.32.0'
22
+ __version_tuple__ = version_tuple = (3, 32, 0)
23
23
 
24
24
  __commit_id__ = commit_id = None
@@ -83,6 +83,8 @@ class AioBaseCursor(BaseCursor):
83
83
  async def __poll(self, query_id: str) -> AthenaQueryExecution:
84
84
  while True:
85
85
  query_execution = await self._get_query_execution(query_id)
86
+ if self._on_poll:
87
+ self._on_poll(query_execution)
86
88
  if query_execution.state in [
87
89
  AthenaQueryExecution.STATE_SUCCEEDED,
88
90
  AthenaQueryExecution.STATE_FAILED,
@@ -128,6 +128,8 @@ class AioSparkCursor(SparkBaseCursor, WithCalculationExecution):
128
128
  async def __poll(self, query_id: str) -> AthenaQueryExecution | AthenaCalculationExecution:
129
129
  while True:
130
130
  calculation_status = await self._get_calculation_execution_status(query_id)
131
+ if self._on_poll:
132
+ self._on_poll(calculation_status)
131
133
  if calculation_status.state in [
132
134
  AthenaCalculationExecutionStatus.STATE_COMPLETED,
133
135
  AthenaCalculationExecutionStatus.STATE_FAILED,
@@ -63,7 +63,6 @@ class ArrowCursor(WithFetch):
63
63
  unload: bool = False,
64
64
  result_reuse_enable: bool = False,
65
65
  result_reuse_minutes: int = CursorIterator.DEFAULT_RESULT_REUSE_MINUTES,
66
- on_start_query_execution: Callable[[str], None] | None = None,
67
66
  connect_timeout: float | None = None,
68
67
  request_timeout: float | None = None,
69
68
  **kwargs,
@@ -82,7 +81,6 @@ class ArrowCursor(WithFetch):
82
81
  unload: Enable UNLOAD for high-performance Parquet output.
83
82
  result_reuse_enable: Enable Athena query result reuse.
84
83
  result_reuse_minutes: Minutes to reuse cached results.
85
- on_start_query_execution: Callback invoked when query starts.
86
84
  connect_timeout: Socket connection timeout in seconds for S3 operations.
87
85
  Defaults to AWS SDK default (typically 1 second) if not specified.
88
86
  request_timeout: Request timeout in seconds for S3 operations.
@@ -113,7 +111,6 @@ class ArrowCursor(WithFetch):
113
111
  **kwargs,
114
112
  )
115
113
  self._unload = unload
116
- self._on_start_query_execution = on_start_query_execution
117
114
  self._connect_timeout = connect_timeout
118
115
  self._request_timeout = request_timeout
119
116
 
@@ -4,6 +4,7 @@ import logging
4
4
  import sys
5
5
  import time
6
6
  from abc import ABCMeta, abstractmethod
7
+ from collections.abc import Callable
7
8
  from datetime import datetime, timedelta, timezone
8
9
  from typing import TYPE_CHECKING, Any, cast
9
10
 
@@ -27,6 +28,14 @@ if TYPE_CHECKING:
27
28
 
28
29
  _logger = logging.getLogger(__name__)
29
30
 
31
+ OnPollCallback = Callable[[AthenaQueryExecution | AthenaCalculationExecutionStatus], None]
32
+ """Type of the optional ``on_poll`` callback.
33
+
34
+ Invoked once per poll iteration with the current execution object: an
35
+ :class:`~pyathena.model.AthenaQueryExecution` for SQL queries, or an
36
+ :class:`~pyathena.model.AthenaCalculationExecutionStatus` for Spark calculations.
37
+ """
38
+
30
39
 
31
40
  class CursorIterator(metaclass=ABCMeta):
32
41
  """Abstract base class providing iteration and result fetching capabilities for cursors.
@@ -164,6 +173,8 @@ class BaseCursor(metaclass=ABCMeta):
164
173
  kill_on_interrupt: bool,
165
174
  result_reuse_enable: bool,
166
175
  result_reuse_minutes: int,
176
+ on_start_query_execution: Callable[[str], None] | None = None,
177
+ on_poll: OnPollCallback | None = None,
167
178
  **kwargs,
168
179
  ) -> None:
169
180
  super().__init__()
@@ -181,6 +192,11 @@ class BaseCursor(metaclass=ABCMeta):
181
192
  self._kill_on_interrupt = kill_on_interrupt
182
193
  self._result_reuse_enable = result_reuse_enable
183
194
  self._result_reuse_minutes = result_reuse_minutes
195
+ # ``on_start_query_execution`` is invoked only by cursors whose ``execute()``
196
+ # supports it (the synchronous cursors). Async/aio/Spark cursors return the
197
+ # query id immediately through their execution model and do not invoke it.
198
+ self._on_start_query_execution = on_start_query_execution
199
+ self._on_poll = on_poll
184
200
 
185
201
  @staticmethod
186
202
  def get_default_converter(unload: bool = False) -> DefaultTypeConverter | Any:
@@ -558,6 +574,8 @@ class BaseCursor(metaclass=ABCMeta):
558
574
  def __poll(self, query_id: str) -> AthenaQueryExecution | AthenaCalculationExecution:
559
575
  while True:
560
576
  query_execution = self._get_query_execution(query_id)
577
+ if self._on_poll:
578
+ self._on_poll(query_execution)
561
579
  if query_execution.state in [
562
580
  AthenaQueryExecution.STATE_SUCCEEDED,
563
581
  AthenaQueryExecution.STATE_FAILED,
@@ -18,7 +18,7 @@ from boto3.session import Session
18
18
  from botocore.config import Config
19
19
 
20
20
  import pyathena
21
- from pyathena.common import BaseCursor, CursorIterator
21
+ from pyathena.common import BaseCursor, CursorIterator, OnPollCallback
22
22
  from pyathena.converter import Converter
23
23
  from pyathena.cursor import Cursor
24
24
  from pyathena.error import NotSupportedError, ProgrammingError
@@ -127,6 +127,7 @@ class Connection(Generic[ConnectionCursor]):
127
127
  result_reuse_enable: bool = ...,
128
128
  result_reuse_minutes: int = ...,
129
129
  on_start_query_execution: Callable[[str], None] | None = ...,
130
+ on_poll: OnPollCallback | None = ...,
130
131
  **kwargs,
131
132
  ) -> None: ...
132
133
 
@@ -158,6 +159,7 @@ class Connection(Generic[ConnectionCursor]):
158
159
  result_reuse_enable: bool = ...,
159
160
  result_reuse_minutes: int = ...,
160
161
  on_start_query_execution: Callable[[str], None] | None = ...,
162
+ on_poll: OnPollCallback | None = ...,
161
163
  **kwargs,
162
164
  ) -> None: ...
163
165
 
@@ -188,6 +190,7 @@ class Connection(Generic[ConnectionCursor]):
188
190
  result_reuse_enable: bool = False,
189
191
  result_reuse_minutes: int = CursorIterator.DEFAULT_RESULT_REUSE_MINUTES,
190
192
  on_start_query_execution: Callable[[str], None] | None = None,
193
+ on_poll: OnPollCallback | None = None,
191
194
  **kwargs,
192
195
  ) -> None:
193
196
  """Initialize a new Athena database connection.
@@ -224,6 +227,10 @@ class Connection(Generic[ConnectionCursor]):
224
227
  result_reuse_enable: Enable Athena query result reuse. Defaults to False.
225
228
  result_reuse_minutes: Minutes to reuse cached results.
226
229
  on_start_query_execution: Callback function called when query starts.
230
+ on_poll: Callback invoked once per poll iteration with the current
231
+ execution object (``AthenaQueryExecution``, or
232
+ ``AthenaCalculationExecutionStatus`` for Spark). Useful for
233
+ monitoring live query progress. Defaults to None.
227
234
  **kwargs: Additional arguments passed to boto3 Session and client.
228
235
 
229
236
  Raises:
@@ -331,6 +338,7 @@ class Connection(Generic[ConnectionCursor]):
331
338
  self.result_reuse_enable = result_reuse_enable
332
339
  self.result_reuse_minutes = result_reuse_minutes
333
340
  self.on_start_query_execution = on_start_query_execution
341
+ self.on_poll = on_poll
334
342
 
335
343
  def _assume_role(
336
344
  self,
@@ -555,6 +563,7 @@ class Connection(Generic[ConnectionCursor]):
555
563
  on_start_query_execution=kwargs.pop(
556
564
  "on_start_query_execution", self.on_start_query_execution
557
565
  ),
566
+ on_poll=kwargs.pop("on_poll", self.on_poll),
558
567
  **kwargs,
559
568
  )
560
569
 
@@ -52,7 +52,6 @@ class Cursor(WithFetch):
52
52
  kill_on_interrupt: bool = True,
53
53
  result_reuse_enable: bool = False,
54
54
  result_reuse_minutes: int = CursorIterator.DEFAULT_RESULT_REUSE_MINUTES,
55
- on_start_query_execution: Callable[[str], None] | None = None,
56
55
  **kwargs,
57
56
  ) -> None:
58
57
  super().__init__(
@@ -69,7 +68,6 @@ class Cursor(WithFetch):
69
68
  **kwargs,
70
69
  )
71
70
  self._result_set_class = AthenaResultSet
72
- self._on_start_query_execution = on_start_query_execution
73
71
 
74
72
  @property
75
73
  def arraysize(self) -> int:
@@ -1409,11 +1409,18 @@ class S3File(AbstractBufferedFile):
1409
1409
  )
1410
1410
 
1411
1411
  def _upload_chunk(self, final: bool = False) -> bool:
1412
+ # The return value controls whether fsspec's flush() resets self.buffer
1413
+ # afterwards: it does so only when this returns a value other than False.
1414
+ # Returning ``not final`` keeps the buffer intact on the final flush so a
1415
+ # deferred commit() (autocommit=False, i.e. inside an fsspec transaction)
1416
+ # can still read the bytes; resetting it there would upload an empty
1417
+ # object for small files. Mid-stream chunks (final=False) return True so
1418
+ # fsspec clears the already-uploaded buffer between parts.
1412
1419
  if self.tell() < self.blocksize:
1413
1420
  # Files smaller than block size in size cannot be multipart uploaded.
1414
1421
  if self.autocommit and final:
1415
1422
  self.commit()
1416
- return True
1423
+ return not final
1417
1424
 
1418
1425
  if not self.multipart_upload:
1419
1426
  raise RuntimeError("Multipart upload is not initialized.")
@@ -1456,7 +1463,7 @@ class S3File(AbstractBufferedFile):
1456
1463
 
1457
1464
  if self.autocommit and final:
1458
1465
  self.commit()
1459
- return True
1466
+ return not final
1460
1467
 
1461
1468
  def commit(self) -> None:
1462
1469
  if self.tell() == 0:
@@ -79,7 +79,6 @@ class PandasCursor(WithFetch):
79
79
  result_reuse_enable: bool = False,
80
80
  result_reuse_minutes: int = CursorIterator.DEFAULT_RESULT_REUSE_MINUTES,
81
81
  auto_optimize_chunksize: bool = False,
82
- on_start_query_execution: Callable[[str], None] | None = None,
83
82
  **kwargs,
84
83
  ) -> None:
85
84
  """Initialize PandasCursor with configuration options.
@@ -105,7 +104,6 @@ class PandasCursor(WithFetch):
105
104
  auto_optimize_chunksize: Enable automatic chunksize determination for
106
105
  large files. Only effective when chunksize is None.
107
106
  Default: False (no automatic chunking).
108
- on_start_query_execution: Callback for query start events.
109
107
  **kwargs: Additional arguments passed to pandas.read_csv.
110
108
  """
111
109
  super().__init__(
@@ -128,7 +126,6 @@ class PandasCursor(WithFetch):
128
126
  self._cache_type = cache_type
129
127
  self._max_workers = max_workers
130
128
  self._auto_optimize_chunksize = auto_optimize_chunksize
131
- self._on_start_query_execution = on_start_query_execution
132
129
 
133
130
  @staticmethod
134
131
  def get_default_converter(
@@ -74,7 +74,6 @@ class PolarsCursor(WithFetch):
74
74
  unload: bool = False,
75
75
  result_reuse_enable: bool = False,
76
76
  result_reuse_minutes: int = CursorIterator.DEFAULT_RESULT_REUSE_MINUTES,
77
- on_start_query_execution: Callable[[str], None] | None = None,
78
77
  block_size: int | None = None,
79
78
  cache_type: str | None = None,
80
79
  max_workers: int = (cpu_count() or 1) * 5,
@@ -95,7 +94,6 @@ class PolarsCursor(WithFetch):
95
94
  unload: Enable UNLOAD for high-performance Parquet output.
96
95
  result_reuse_enable: Enable Athena query result reuse.
97
96
  result_reuse_minutes: Minutes to reuse cached results.
98
- on_start_query_execution: Callback invoked when query starts.
99
97
  block_size: S3 read block size.
100
98
  cache_type: S3 caching strategy.
101
99
  max_workers: Maximum worker threads for parallel S3 operations.
@@ -123,7 +121,6 @@ class PolarsCursor(WithFetch):
123
121
  **kwargs,
124
122
  )
125
123
  self._unload = unload
126
- self._on_start_query_execution = on_start_query_execution
127
124
  self._block_size = block_size
128
125
  self._cache_type = cache_type
129
126
  self._max_workers = max_workers
@@ -58,7 +58,6 @@ class S3FSCursor(WithFetch):
58
58
  kill_on_interrupt: bool = True,
59
59
  result_reuse_enable: bool = False,
60
60
  result_reuse_minutes: int = CursorIterator.DEFAULT_RESULT_REUSE_MINUTES,
61
- on_start_query_execution: Callable[[str], None] | None = None,
62
61
  csv_reader: CSVReaderType | None = None,
63
62
  **kwargs,
64
63
  ) -> None:
@@ -75,7 +74,6 @@ class S3FSCursor(WithFetch):
75
74
  kill_on_interrupt: Cancel running query on keyboard interrupt.
76
75
  result_reuse_enable: Enable Athena query result reuse.
77
76
  result_reuse_minutes: Minutes to reuse cached results.
78
- on_start_query_execution: Callback invoked when query starts.
79
77
  csv_reader: CSV reader class to use for parsing results.
80
78
  Use AthenaCSVReader (default) to distinguish between NULL
81
79
  (unquoted empty) and empty string (quoted empty "").
@@ -104,7 +102,6 @@ class S3FSCursor(WithFetch):
104
102
  result_reuse_minutes=result_reuse_minutes,
105
103
  **kwargs,
106
104
  )
107
- self._on_start_query_execution = on_start_query_execution
108
105
  self._csv_reader = csv_reader
109
106
 
110
107
  @staticmethod
@@ -201,6 +201,8 @@ class SparkBaseCursor(BaseCursor, metaclass=ABCMeta):
201
201
  def __poll(self, query_id: str) -> AthenaQueryExecution | AthenaCalculationExecution:
202
202
  while True:
203
203
  calculation_status = self._get_calculation_execution_status(query_id)
204
+ if self._on_poll:
205
+ self._on_poll(calculation_status)
204
206
  if calculation_status.state in [
205
207
  AthenaCalculationExecutionStatus.STATE_COMPLETED,
206
208
  AthenaCalculationExecutionStatus.STATE_FAILED,
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes