PyAthena 3.27.2__tar.gz → 3.29.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 (79) hide show
  1. {pyathena-3.27.2 → pyathena-3.29.0}/PKG-INFO +19 -3
  2. {pyathena-3.27.2 → pyathena-3.29.0}/README.md +17 -1
  3. {pyathena-3.27.2 → pyathena-3.29.0}/pyathena/__init__.py +34 -1
  4. {pyathena-3.27.2 → pyathena-3.29.0}/pyathena/_version.py +2 -2
  5. pyathena-3.29.0/pyathena/aio/arrow/cursor.py +230 -0
  6. pyathena-3.29.0/pyathena/aio/common.py +500 -0
  7. pyathena-3.29.0/pyathena/aio/connection.py +54 -0
  8. pyathena-3.29.0/pyathena/aio/cursor.py +204 -0
  9. pyathena-3.29.0/pyathena/aio/pandas/cursor.py +251 -0
  10. pyathena-3.29.0/pyathena/aio/polars/cursor.py +238 -0
  11. pyathena-3.29.0/pyathena/aio/result_set.py +203 -0
  12. pyathena-3.29.0/pyathena/aio/s3fs/cursor.py +200 -0
  13. pyathena-3.29.0/pyathena/aio/spark/__init__.py +1 -0
  14. pyathena-3.29.0/pyathena/aio/spark/cursor.py +285 -0
  15. pyathena-3.29.0/pyathena/aio/util.py +33 -0
  16. pyathena-3.29.0/pyathena/arrow/__init__.py +1 -0
  17. {pyathena-3.27.2 → pyathena-3.29.0}/pyathena/arrow/async_cursor.py +2 -12
  18. {pyathena-3.27.2 → pyathena-3.29.0}/pyathena/arrow/cursor.py +6 -97
  19. {pyathena-3.27.2 → pyathena-3.29.0}/pyathena/arrow/result_set.py +21 -0
  20. {pyathena-3.27.2 → pyathena-3.29.0}/pyathena/async_cursor.py +1 -2
  21. {pyathena-3.27.2 → pyathena-3.29.0}/pyathena/common.py +76 -14
  22. {pyathena-3.27.2 → pyathena-3.29.0}/pyathena/connection.py +18 -8
  23. pyathena-3.29.0/pyathena/cursor.py +181 -0
  24. pyathena-3.29.0/pyathena/filesystem/__init__.py +1 -0
  25. {pyathena-3.27.2 → pyathena-3.29.0}/pyathena/formatter.py +2 -2
  26. {pyathena-3.27.2 → pyathena-3.29.0}/pyathena/pandas/async_cursor.py +2 -12
  27. {pyathena-3.27.2 → pyathena-3.29.0}/pyathena/pandas/cursor.py +4 -97
  28. {pyathena-3.27.2 → pyathena-3.29.0}/pyathena/pandas/result_set.py +22 -0
  29. {pyathena-3.27.2 → pyathena-3.29.0}/pyathena/polars/async_cursor.py +2 -12
  30. {pyathena-3.27.2 → pyathena-3.29.0}/pyathena/polars/cursor.py +5 -151
  31. {pyathena-3.27.2 → pyathena-3.29.0}/pyathena/polars/result_set.py +30 -8
  32. {pyathena-3.27.2 → pyathena-3.29.0}/pyathena/result_set.py +266 -24
  33. pyathena-3.29.0/pyathena/s3fs/__init__.py +1 -0
  34. {pyathena-3.27.2 → pyathena-3.29.0}/pyathena/s3fs/cursor.py +5 -140
  35. {pyathena-3.27.2 → pyathena-3.29.0}/pyathena/s3fs/result_set.py +5 -1
  36. pyathena-3.29.0/pyathena/spark/__init__.py +1 -0
  37. pyathena-3.29.0/pyathena/sqlalchemy/__init__.py +1 -0
  38. {pyathena-3.27.2 → pyathena-3.29.0}/pyproject.toml +4 -1
  39. pyathena-3.27.2/pyathena/cursor.py +0 -394
  40. {pyathena-3.27.2 → pyathena-3.29.0}/.gitignore +0 -0
  41. {pyathena-3.27.2 → pyathena-3.29.0}/LICENSE +0 -0
  42. {pyathena-3.27.2/pyathena/arrow → pyathena-3.29.0/pyathena/aio}/__init__.py +0 -0
  43. {pyathena-3.27.2/pyathena/filesystem → pyathena-3.29.0/pyathena/aio/arrow}/__init__.py +0 -0
  44. {pyathena-3.27.2/pyathena/s3fs → pyathena-3.29.0/pyathena/aio/pandas}/__init__.py +0 -0
  45. {pyathena-3.27.2/pyathena/spark → pyathena-3.29.0/pyathena/aio/polars}/__init__.py +0 -0
  46. {pyathena-3.27.2/pyathena/sqlalchemy → pyathena-3.29.0/pyathena/aio/s3fs}/__init__.py +0 -0
  47. {pyathena-3.27.2 → pyathena-3.29.0}/pyathena/arrow/converter.py +0 -0
  48. {pyathena-3.27.2 → pyathena-3.29.0}/pyathena/arrow/util.py +0 -0
  49. {pyathena-3.27.2 → pyathena-3.29.0}/pyathena/converter.py +0 -0
  50. {pyathena-3.27.2 → pyathena-3.29.0}/pyathena/error.py +0 -0
  51. {pyathena-3.27.2 → pyathena-3.29.0}/pyathena/filesystem/s3.py +0 -0
  52. {pyathena-3.27.2 → pyathena-3.29.0}/pyathena/filesystem/s3_object.py +0 -0
  53. {pyathena-3.27.2 → pyathena-3.29.0}/pyathena/model.py +0 -0
  54. {pyathena-3.27.2 → pyathena-3.29.0}/pyathena/pandas/__init__.py +0 -0
  55. {pyathena-3.27.2 → pyathena-3.29.0}/pyathena/pandas/converter.py +0 -0
  56. {pyathena-3.27.2 → pyathena-3.29.0}/pyathena/pandas/util.py +0 -0
  57. {pyathena-3.27.2 → pyathena-3.29.0}/pyathena/polars/__init__.py +0 -0
  58. {pyathena-3.27.2 → pyathena-3.29.0}/pyathena/polars/converter.py +0 -0
  59. {pyathena-3.27.2 → pyathena-3.29.0}/pyathena/polars/util.py +0 -0
  60. {pyathena-3.27.2 → pyathena-3.29.0}/pyathena/py.typed +0 -0
  61. {pyathena-3.27.2 → pyathena-3.29.0}/pyathena/s3fs/async_cursor.py +0 -0
  62. {pyathena-3.27.2 → pyathena-3.29.0}/pyathena/s3fs/converter.py +0 -0
  63. {pyathena-3.27.2 → pyathena-3.29.0}/pyathena/s3fs/reader.py +0 -0
  64. {pyathena-3.27.2 → pyathena-3.29.0}/pyathena/spark/async_cursor.py +0 -0
  65. {pyathena-3.27.2 → pyathena-3.29.0}/pyathena/spark/common.py +0 -0
  66. {pyathena-3.27.2 → pyathena-3.29.0}/pyathena/spark/cursor.py +0 -0
  67. {pyathena-3.27.2 → pyathena-3.29.0}/pyathena/sqlalchemy/arrow.py +0 -0
  68. {pyathena-3.27.2 → pyathena-3.29.0}/pyathena/sqlalchemy/base.py +0 -0
  69. {pyathena-3.27.2 → pyathena-3.29.0}/pyathena/sqlalchemy/compiler.py +0 -0
  70. {pyathena-3.27.2 → pyathena-3.29.0}/pyathena/sqlalchemy/constants.py +0 -0
  71. {pyathena-3.27.2 → pyathena-3.29.0}/pyathena/sqlalchemy/pandas.py +0 -0
  72. {pyathena-3.27.2 → pyathena-3.29.0}/pyathena/sqlalchemy/polars.py +0 -0
  73. {pyathena-3.27.2 → pyathena-3.29.0}/pyathena/sqlalchemy/preparer.py +0 -0
  74. {pyathena-3.27.2 → pyathena-3.29.0}/pyathena/sqlalchemy/requirements.py +0 -0
  75. {pyathena-3.27.2 → pyathena-3.29.0}/pyathena/sqlalchemy/rest.py +0 -0
  76. {pyathena-3.27.2 → pyathena-3.29.0}/pyathena/sqlalchemy/s3fs.py +0 -0
  77. {pyathena-3.27.2 → pyathena-3.29.0}/pyathena/sqlalchemy/types.py +0 -0
  78. {pyathena-3.27.2 → pyathena-3.29.0}/pyathena/sqlalchemy/util.py +0 -0
  79. {pyathena-3.27.2 → pyathena-3.29.0}/pyathena/util.py +0 -0
@@ -1,10 +1,10 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: PyAthena
3
- Version: 3.27.2
3
+ Version: 3.29.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/
7
- Project-URL: documentation, https://pyathena-dev.github.io/PyAthena/
7
+ Project-URL: documentation, https://pyathena.dev/
8
8
  Project-URL: issues, https://github.com/pyathena-dev/PyAthena/issues
9
9
  Author-email: laughingman7743 <laughingman7743@gmail.com>
10
10
  License: Copyright 2017 laughingman7743
@@ -109,6 +109,22 @@ print(cursor.description)
109
109
  print(cursor.fetchall())
110
110
  ```
111
111
 
112
+ Native asyncio is also supported:
113
+
114
+ ```python
115
+ import asyncio
116
+ from pyathena import aconnect
117
+
118
+ async def main():
119
+ async with await aconnect(s3_staging_dir="s3://YOUR_S3_BUCKET/path/to/",
120
+ region_name="us-west-2") as conn:
121
+ cursor = conn.cursor()
122
+ await cursor.execute("SELECT 1")
123
+ print(await cursor.fetchone())
124
+
125
+ asyncio.run(main())
126
+ ```
127
+
112
128
  ## License
113
129
 
114
130
  [MIT license](LICENSE)
@@ -117,7 +133,7 @@ Many of the implementations in this library are based on [PyHive](https://github
117
133
 
118
134
  ## Links
119
135
 
120
- - Documentation: https://pyathena-dev.github.io/PyAthena/
136
+ - Documentation: https://pyathena.dev/
121
137
  - PyPI Releases: https://pypi.org/project/PyAthena/
122
138
  - Source Code: https://github.com/pyathena-dev/PyAthena/
123
139
  - Issue Tracker: https://github.com/pyathena-dev/PyAthena/issues
@@ -52,6 +52,22 @@ print(cursor.description)
52
52
  print(cursor.fetchall())
53
53
  ```
54
54
 
55
+ Native asyncio is also supported:
56
+
57
+ ```python
58
+ import asyncio
59
+ from pyathena import aconnect
60
+
61
+ async def main():
62
+ async with await aconnect(s3_staging_dir="s3://YOUR_S3_BUCKET/path/to/",
63
+ region_name="us-west-2") as conn:
64
+ cursor = conn.cursor()
65
+ await cursor.execute("SELECT 1")
66
+ print(await cursor.fetchone())
67
+
68
+ asyncio.run(main())
69
+ ```
70
+
55
71
  ## License
56
72
 
57
73
  [MIT license](LICENSE)
@@ -60,7 +76,7 @@ Many of the implementations in this library are based on [PyHive](https://github
60
76
 
61
77
  ## Links
62
78
 
63
- - Documentation: https://pyathena-dev.github.io/PyAthena/
79
+ - Documentation: https://pyathena.dev/
64
80
  - PyPI Releases: https://pypi.org/project/PyAthena/
65
81
  - Source Code: https://github.com/pyathena-dev/PyAthena/
66
82
  - Issue Tracker: https://github.com/pyathena-dev/PyAthena/issues
@@ -7,6 +7,7 @@ from typing import TYPE_CHECKING, Any, FrozenSet, Type, overload
7
7
  from pyathena.error import * # noqa
8
8
 
9
9
  if TYPE_CHECKING:
10
+ from pyathena.aio.connection import AioConnection
10
11
  from pyathena.connection import Connection, ConnectionCursor
11
12
  from pyathena.cursor import Cursor
12
13
 
@@ -85,6 +86,9 @@ def connect(*args, **kwargs) -> "Connection[Any]":
85
86
  Args:
86
87
  s3_staging_dir: S3 location to store query results. Required if not
87
88
  using workgroups or if the workgroup doesn't have a result location.
89
+ Pass an empty string to explicitly disable S3 staging and skip
90
+ the ``AWS_ATHENA_S3_STAGING_DIR`` environment variable fallback
91
+ (required for workgroups with managed query result storage).
88
92
  region_name: AWS region name. If not specified, uses the default region
89
93
  from your AWS configuration.
90
94
  schema_name: Athena database/schema name. Defaults to "default".
@@ -109,7 +113,7 @@ def connect(*args, **kwargs) -> "Connection[Any]":
109
113
  A Connection object that can be used to create cursors and execute queries.
110
114
 
111
115
  Raises:
112
- AssertionError: If neither s3_staging_dir nor work_group is provided.
116
+ ProgrammingError: If neither s3_staging_dir nor work_group is provided.
113
117
 
114
118
  Example:
115
119
  >>> import pyathena
@@ -125,3 +129,32 @@ def connect(*args, **kwargs) -> "Connection[Any]":
125
129
  from pyathena.connection import Connection
126
130
 
127
131
  return Connection(*args, **kwargs)
132
+
133
+
134
+ async def aconnect(*args, **kwargs) -> "AioConnection":
135
+ """Create a new async database connection to Amazon Athena.
136
+
137
+ This is the async counterpart of :func:`connect`. It returns an
138
+ ``AioConnection`` whose cursors use native ``asyncio`` for polling
139
+ and API calls, keeping the event loop free.
140
+
141
+ Args:
142
+ **kwargs: Arguments forwarded to ``AioConnection.create()``.
143
+ See :func:`connect` for the full list of supported arguments.
144
+
145
+ Returns:
146
+ An ``AioConnection`` that produces ``AioCursor`` instances by default.
147
+
148
+ Example:
149
+ >>> import pyathena
150
+ >>> conn = await pyathena.aconnect(
151
+ ... s3_staging_dir='s3://my-bucket/staging/',
152
+ ... region_name='us-east-1',
153
+ ... )
154
+ >>> async with conn.cursor() as cursor:
155
+ ... await cursor.execute("SELECT 1")
156
+ ... print(await cursor.fetchone())
157
+ """
158
+ from pyathena.aio.connection import AioConnection
159
+
160
+ return await AioConnection.create(*args, **kwargs)
@@ -28,7 +28,7 @@ version_tuple: VERSION_TUPLE
28
28
  commit_id: COMMIT_ID
29
29
  __commit_id__: COMMIT_ID
30
30
 
31
- __version__ = version = '3.27.2'
32
- __version_tuple__ = version_tuple = (3, 27, 2)
31
+ __version__ = version = '3.29.0'
32
+ __version_tuple__ = version_tuple = (3, 29, 0)
33
33
 
34
34
  __commit_id__ = commit_id = None
@@ -0,0 +1,230 @@
1
+ # -*- coding: utf-8 -*-
2
+ from __future__ import annotations
3
+
4
+ import asyncio
5
+ import logging
6
+ from typing import TYPE_CHECKING, Any, Dict, List, Optional, Tuple, Union, cast
7
+
8
+ from pyathena.aio.common import WithAsyncFetch
9
+ from pyathena.arrow.converter import (
10
+ DefaultArrowTypeConverter,
11
+ DefaultArrowUnloadTypeConverter,
12
+ )
13
+ from pyathena.arrow.result_set import AthenaArrowResultSet
14
+ from pyathena.common import CursorIterator
15
+ from pyathena.error import OperationalError, ProgrammingError
16
+ from pyathena.model import AthenaQueryExecution
17
+
18
+ if TYPE_CHECKING:
19
+ import polars as pl
20
+ from pyarrow import Table
21
+
22
+ _logger = logging.getLogger(__name__) # type: ignore
23
+
24
+
25
+ class AioArrowCursor(WithAsyncFetch):
26
+ """Native asyncio cursor that returns results as Apache Arrow Tables.
27
+
28
+ Uses ``asyncio.to_thread()`` for both result set creation and fetch
29
+ operations, keeping the event loop free.
30
+
31
+ Example:
32
+ >>> async with await pyathena.aconnect(...) as conn:
33
+ ... cursor = conn.cursor(AioArrowCursor)
34
+ ... await cursor.execute("SELECT * FROM my_table")
35
+ ... table = cursor.as_arrow()
36
+ """
37
+
38
+ def __init__(
39
+ self,
40
+ s3_staging_dir: Optional[str] = None,
41
+ schema_name: Optional[str] = None,
42
+ catalog_name: Optional[str] = None,
43
+ work_group: Optional[str] = None,
44
+ poll_interval: float = 1,
45
+ encryption_option: Optional[str] = None,
46
+ kms_key: Optional[str] = None,
47
+ kill_on_interrupt: bool = True,
48
+ unload: bool = False,
49
+ result_reuse_enable: bool = False,
50
+ result_reuse_minutes: int = CursorIterator.DEFAULT_RESULT_REUSE_MINUTES,
51
+ connect_timeout: Optional[float] = None,
52
+ request_timeout: Optional[float] = None,
53
+ **kwargs,
54
+ ) -> None:
55
+ super().__init__(
56
+ s3_staging_dir=s3_staging_dir,
57
+ schema_name=schema_name,
58
+ catalog_name=catalog_name,
59
+ work_group=work_group,
60
+ poll_interval=poll_interval,
61
+ encryption_option=encryption_option,
62
+ kms_key=kms_key,
63
+ kill_on_interrupt=kill_on_interrupt,
64
+ result_reuse_enable=result_reuse_enable,
65
+ result_reuse_minutes=result_reuse_minutes,
66
+ **kwargs,
67
+ )
68
+ self._unload = unload
69
+ self._connect_timeout = connect_timeout
70
+ self._request_timeout = request_timeout
71
+ self._result_set: Optional[AthenaArrowResultSet] = None
72
+
73
+ @staticmethod
74
+ def get_default_converter(
75
+ unload: bool = False,
76
+ ) -> Union[DefaultArrowTypeConverter, DefaultArrowUnloadTypeConverter, Any]:
77
+ if unload:
78
+ return DefaultArrowUnloadTypeConverter()
79
+ return DefaultArrowTypeConverter()
80
+
81
+ async def execute( # type: ignore[override]
82
+ self,
83
+ operation: str,
84
+ parameters: Optional[Union[Dict[str, Any], List[str]]] = None,
85
+ work_group: Optional[str] = None,
86
+ s3_staging_dir: Optional[str] = None,
87
+ cache_size: Optional[int] = 0,
88
+ cache_expiration_time: Optional[int] = 0,
89
+ result_reuse_enable: Optional[bool] = None,
90
+ result_reuse_minutes: Optional[int] = None,
91
+ paramstyle: Optional[str] = None,
92
+ **kwargs,
93
+ ) -> "AioArrowCursor":
94
+ """Execute a SQL query asynchronously and return results as Arrow Tables.
95
+
96
+ Args:
97
+ operation: SQL query string to execute.
98
+ parameters: Query parameters for parameterized queries.
99
+ work_group: Athena workgroup to use for this query.
100
+ s3_staging_dir: S3 location for query results.
101
+ cache_size: Number of queries to check for result caching.
102
+ cache_expiration_time: Cache expiration time in seconds.
103
+ result_reuse_enable: Enable Athena result reuse for this query.
104
+ result_reuse_minutes: Minutes to reuse cached results.
105
+ paramstyle: Parameter style ('qmark' or 'pyformat').
106
+ **kwargs: Additional execution parameters.
107
+
108
+ Returns:
109
+ Self reference for method chaining.
110
+ """
111
+ self._reset_state()
112
+ operation, unload_location = self._prepare_unload(operation, s3_staging_dir)
113
+ self.query_id = await self._execute(
114
+ operation,
115
+ parameters=parameters,
116
+ work_group=work_group,
117
+ s3_staging_dir=s3_staging_dir,
118
+ cache_size=cache_size,
119
+ cache_expiration_time=cache_expiration_time,
120
+ result_reuse_enable=result_reuse_enable,
121
+ result_reuse_minutes=result_reuse_minutes,
122
+ paramstyle=paramstyle,
123
+ )
124
+
125
+ query_execution = await self._poll(self.query_id)
126
+ if query_execution.state == AthenaQueryExecution.STATE_SUCCEEDED:
127
+ self.result_set = await asyncio.to_thread(
128
+ AthenaArrowResultSet,
129
+ connection=self._connection,
130
+ converter=self._converter,
131
+ query_execution=query_execution,
132
+ arraysize=self.arraysize,
133
+ retry_config=self._retry_config,
134
+ unload=self._unload,
135
+ unload_location=unload_location,
136
+ connect_timeout=self._connect_timeout,
137
+ request_timeout=self._request_timeout,
138
+ **kwargs,
139
+ )
140
+ else:
141
+ raise OperationalError(query_execution.state_change_reason)
142
+ return self
143
+
144
+ async def fetchone( # type: ignore[override]
145
+ self,
146
+ ) -> Optional[Union[Tuple[Optional[Any], ...], Dict[Any, Optional[Any]]]]:
147
+ """Fetch the next row of the result set.
148
+
149
+ Wraps the synchronous fetch in ``asyncio.to_thread`` to avoid
150
+ blocking the event loop.
151
+
152
+ Returns:
153
+ A tuple representing the next row, or None if no more rows.
154
+
155
+ Raises:
156
+ ProgrammingError: If no result set is available.
157
+ """
158
+ if not self.has_result_set:
159
+ raise ProgrammingError("No result set.")
160
+ result_set = cast(AthenaArrowResultSet, self.result_set)
161
+ return await asyncio.to_thread(result_set.fetchone)
162
+
163
+ async def fetchmany( # type: ignore[override]
164
+ self, size: Optional[int] = None
165
+ ) -> List[Union[Tuple[Optional[Any], ...], Dict[Any, Optional[Any]]]]:
166
+ """Fetch multiple rows from the result set.
167
+
168
+ Wraps the synchronous fetch in ``asyncio.to_thread`` to avoid
169
+ blocking the event loop.
170
+
171
+ Args:
172
+ size: Maximum number of rows to fetch. Defaults to arraysize.
173
+
174
+ Returns:
175
+ List of tuples representing the fetched rows.
176
+
177
+ Raises:
178
+ ProgrammingError: If no result set is available.
179
+ """
180
+ if not self.has_result_set:
181
+ raise ProgrammingError("No result set.")
182
+ result_set = cast(AthenaArrowResultSet, self.result_set)
183
+ return await asyncio.to_thread(result_set.fetchmany, size)
184
+
185
+ async def fetchall( # type: ignore[override]
186
+ self,
187
+ ) -> List[Union[Tuple[Optional[Any], ...], Dict[Any, Optional[Any]]]]:
188
+ """Fetch all remaining rows from the result set.
189
+
190
+ Wraps the synchronous fetch in ``asyncio.to_thread`` to avoid
191
+ blocking the event loop.
192
+
193
+ Returns:
194
+ List of tuples representing all remaining rows.
195
+
196
+ Raises:
197
+ ProgrammingError: If no result set is available.
198
+ """
199
+ if not self.has_result_set:
200
+ raise ProgrammingError("No result set.")
201
+ result_set = cast(AthenaArrowResultSet, self.result_set)
202
+ return await asyncio.to_thread(result_set.fetchall)
203
+
204
+ async def __anext__(self):
205
+ row = await self.fetchone()
206
+ if row is None:
207
+ raise StopAsyncIteration
208
+ return row
209
+
210
+ def as_arrow(self) -> "Table":
211
+ """Return query results as an Apache Arrow Table.
212
+
213
+ Returns:
214
+ Apache Arrow Table containing all query results.
215
+ """
216
+ if not self.has_result_set:
217
+ raise ProgrammingError("No result set.")
218
+ result_set = cast(AthenaArrowResultSet, self.result_set)
219
+ return result_set.as_arrow()
220
+
221
+ def as_polars(self) -> "pl.DataFrame":
222
+ """Return query results as a Polars DataFrame.
223
+
224
+ Returns:
225
+ Polars DataFrame containing all query results.
226
+ """
227
+ if not self.has_result_set:
228
+ raise ProgrammingError("No result set.")
229
+ result_set = cast(AthenaArrowResultSet, self.result_set)
230
+ return result_set.as_polars()