Skip to content

Commit 3abb567

Browse files
Expand ruff lint rules and rename make chk to make lint
Add 11 new ruff lint rule categories (UP, PIE, PERF, T20, FLY, ISC, RSE, RUF, PGH, G, PT) and fix all violations across the codebase. Key changes: - Rename `make chk` to `make lint` in Makefile, CLAUDE.md, and docs - Modernize type annotations (Union → X|Y, Optional → X|None) - Convert f-string logging to lazy % formatting (G004/G003) - Replace blanket `# type: ignore` with specific error codes (PGH003) - Add ClassVar annotations for mutable class attributes (RUF012) - Add match parameters to pytest.raises(ValueError) calls (PT011) - Extract setup from pytest.raises blocks (PT012) - Use tuple for pytest.mark.parametrize names (PT006) - Replace yield-for-loop with yield from (UP028) - Use collection unpacking instead of concatenation (RUF005) - Add per-file-ignores for SQLAlchemy naming conventions (N802, N801) - Suppress PEP 249 required names that conflict with lint rules (B027, N818) - Exclude benchmarks directory from ruff checking Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 7c0eb56 commit 3abb567

File tree

138 files changed

+1915
-2088
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

138 files changed

+1915
-2088
lines changed

CLAUDE.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,12 +17,12 @@ PyAthena is a Python DB API 2.0 (PEP 249) compliant client for Amazon Athena. Se
1717
### Code Quality — Always Run Before Committing
1818
```bash
1919
make fmt # Auto-fix formatting and imports
20-
make chk # Lint + format check + mypy
20+
make lint # Lint + format check + mypy
2121
```
2222

2323
### Testing
2424
```bash
25-
# ALWAYS run `make chk` first — tests will fail if lint doesn't pass
25+
# ALWAYS run `make lint` first — tests will fail if lint doesn't pass
2626
make test # Unit tests (runs chk first)
2727
make test-sqla # SQLAlchemy dialect tests
2828
```

Makefile

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,14 @@ fmt:
77
uvx ruff@$(RUFF_VERSION) check --select I --fix .
88
uvx ruff@$(RUFF_VERSION) format .
99

10-
.PHONY: chk
11-
chk:
10+
.PHONY: lint
11+
lint:
1212
uvx ruff@$(RUFF_VERSION) check .
1313
uvx ruff@$(RUFF_VERSION) format --check .
1414
uv run mypy .
1515

1616
.PHONY: test
17-
test: chk
17+
test: lint
1818
uv run pytest -n 8 --cov pyathena --cov-report html --cov-report term tests/pyathena/
1919

2020
.PHONY: test-sqla

docs/testing.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -54,10 +54,10 @@ The code formatting uses [ruff](https://github.com/astral-sh/ruff).
5454
$ make fmt
5555
```
5656

57-
### Check format
57+
### Lint and check format
5858

5959
```bash
60-
$ make chk
60+
$ make lint
6161
```
6262

6363
## GitHub Actions

pyathena/__init__.py

Lines changed: 11 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,9 @@
1-
# -*- coding: utf-8 -*-
21
from __future__ import annotations
32

43
import datetime
5-
from typing import TYPE_CHECKING, Any, FrozenSet, Type, overload
4+
from typing import TYPE_CHECKING, Any, overload
65

7-
from pyathena.error import * # noqa
6+
from pyathena.error import * # noqa: F403
87

98
if TYPE_CHECKING:
109
from pyathena.aio.connection import AioConnection
@@ -28,7 +27,7 @@
2827
paramstyle: str = "pyformat"
2928

3029

31-
class DBAPITypeObject(FrozenSet[str]):
30+
class DBAPITypeObject(frozenset[str]):
3231
"""Type Objects and Constructors
3332
3433
https://www.python.org/dev/peps/pep-0249/#type-objects-and-constructors
@@ -60,22 +59,22 @@ def __hash__(self):
6059
DATETIME: DBAPITypeObject = DBAPITypeObject(("timestamp", "timestamp with time zone"))
6160
JSON: DBAPITypeObject = DBAPITypeObject(("json",))
6261

63-
Date: Type[datetime.date] = datetime.date
64-
Time: Type[datetime.time] = datetime.time
65-
Timestamp: Type[datetime.datetime] = datetime.datetime
62+
Date: type[datetime.date] = datetime.date
63+
Time: type[datetime.time] = datetime.time
64+
Timestamp: type[datetime.datetime] = datetime.datetime
6665

6766

6867
@overload
69-
def connect(*args, cursor_class: None = ..., **kwargs) -> "Connection[Cursor]": ...
68+
def connect(*args, cursor_class: None = ..., **kwargs) -> Connection[Cursor]: ...
7069

7170

7271
@overload
7372
def connect(
74-
*args, cursor_class: Type[ConnectionCursor], **kwargs
75-
) -> "Connection[ConnectionCursor]": ...
73+
*args, cursor_class: type[ConnectionCursor], **kwargs
74+
) -> Connection[ConnectionCursor]: ...
7675

7776

78-
def connect(*args, **kwargs) -> "Connection[Any]":
77+
def connect(*args, **kwargs) -> Connection[Any]:
7978
"""Create a new database connection to Amazon Athena.
8079
8180
This function provides the main entry point for establishing connections
@@ -131,7 +130,7 @@ def connect(*args, **kwargs) -> "Connection[Any]":
131130
return Connection(*args, **kwargs)
132131

133132

134-
async def aio_connect(*args, **kwargs) -> "AioConnection":
133+
async def aio_connect(*args, **kwargs) -> AioConnection:
135134
"""Create a new async database connection to Amazon Athena.
136135
137136
This is the async counterpart of :func:`connect`. It returns an

pyathena/aio/__init__.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +0,0 @@
1-
# -*- coding: utf-8 -*-

pyathena/aio/arrow/__init__.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +0,0 @@
1-
# -*- coding: utf-8 -*-

pyathena/aio/arrow/cursor.py

Lines changed: 27 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,8 @@
1-
# -*- coding: utf-8 -*-
21
from __future__ import annotations
32

43
import asyncio
54
import logging
6-
from typing import TYPE_CHECKING, Any, Dict, List, Optional, Tuple, Union, cast
5+
from typing import TYPE_CHECKING, Any, cast
76

87
from pyathena.aio.common import WithAsyncFetch
98
from pyathena.arrow.converter import (
@@ -19,7 +18,7 @@
1918
import polars as pl
2019
from pyarrow import Table
2120

22-
_logger = logging.getLogger(__name__) # type: ignore
21+
_logger = logging.getLogger(__name__)
2322

2423

2524
class AioArrowCursor(WithAsyncFetch):
@@ -37,19 +36,19 @@ class AioArrowCursor(WithAsyncFetch):
3736

3837
def __init__(
3938
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,
39+
s3_staging_dir: str | None = None,
40+
schema_name: str | None = None,
41+
catalog_name: str | None = None,
42+
work_group: str | None = None,
4443
poll_interval: float = 1,
45-
encryption_option: Optional[str] = None,
46-
kms_key: Optional[str] = None,
44+
encryption_option: str | None = None,
45+
kms_key: str | None = None,
4746
kill_on_interrupt: bool = True,
4847
unload: bool = False,
4948
result_reuse_enable: bool = False,
5049
result_reuse_minutes: int = CursorIterator.DEFAULT_RESULT_REUSE_MINUTES,
51-
connect_timeout: Optional[float] = None,
52-
request_timeout: Optional[float] = None,
50+
connect_timeout: float | None = None,
51+
request_timeout: float | None = None,
5352
**kwargs,
5453
) -> None:
5554
super().__init__(
@@ -68,29 +67,29 @@ def __init__(
6867
self._unload = unload
6968
self._connect_timeout = connect_timeout
7069
self._request_timeout = request_timeout
71-
self._result_set: Optional[AthenaArrowResultSet] = None
70+
self._result_set: AthenaArrowResultSet | None = None
7271

7372
@staticmethod
7473
def get_default_converter(
7574
unload: bool = False,
76-
) -> Union[DefaultArrowTypeConverter, DefaultArrowUnloadTypeConverter, Any]:
75+
) -> DefaultArrowTypeConverter | DefaultArrowUnloadTypeConverter | Any:
7776
if unload:
7877
return DefaultArrowUnloadTypeConverter()
7978
return DefaultArrowTypeConverter()
8079

8180
async def execute( # type: ignore[override]
8281
self,
8382
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,
83+
parameters: dict[str, Any] | list[str] | None = None,
84+
work_group: str | None = None,
85+
s3_staging_dir: str | None = None,
86+
cache_size: int | None = 0,
87+
cache_expiration_time: int | None = 0,
88+
result_reuse_enable: bool | None = None,
89+
result_reuse_minutes: int | None = None,
90+
paramstyle: str | None = None,
9291
**kwargs,
93-
) -> "AioArrowCursor":
92+
) -> AioArrowCursor:
9493
"""Execute a SQL query asynchronously and return results as Arrow Tables.
9594
9695
Args:
@@ -143,7 +142,7 @@ async def execute( # type: ignore[override]
143142

144143
async def fetchone( # type: ignore[override]
145144
self,
146-
) -> Optional[Union[Tuple[Optional[Any], ...], Dict[Any, Optional[Any]]]]:
145+
) -> tuple[Any | None, ...] | dict[Any, Any | None] | None:
147146
"""Fetch the next row of the result set.
148147
149148
Wraps the synchronous fetch in ``asyncio.to_thread`` to avoid
@@ -161,8 +160,8 @@ async def fetchone( # type: ignore[override]
161160
return await asyncio.to_thread(result_set.fetchone)
162161

163162
async def fetchmany( # type: ignore[override]
164-
self, size: Optional[int] = None
165-
) -> List[Union[Tuple[Optional[Any], ...], Dict[Any, Optional[Any]]]]:
163+
self, size: int | None = None
164+
) -> list[tuple[Any | None, ...] | dict[Any, Any | None]]:
166165
"""Fetch multiple rows from the result set.
167166
168167
Wraps the synchronous fetch in ``asyncio.to_thread`` to avoid
@@ -184,7 +183,7 @@ async def fetchmany( # type: ignore[override]
184183

185184
async def fetchall( # type: ignore[override]
186185
self,
187-
) -> List[Union[Tuple[Optional[Any], ...], Dict[Any, Optional[Any]]]]:
186+
) -> list[tuple[Any | None, ...] | dict[Any, Any | None]]:
188187
"""Fetch all remaining rows from the result set.
189188
190189
Wraps the synchronous fetch in ``asyncio.to_thread`` to avoid
@@ -207,7 +206,7 @@ async def __anext__(self):
207206
raise StopAsyncIteration
208207
return row
209208

210-
def as_arrow(self) -> "Table":
209+
def as_arrow(self) -> Table:
211210
"""Return query results as an Apache Arrow Table.
212211
213212
Returns:
@@ -218,7 +217,7 @@ def as_arrow(self) -> "Table":
218217
result_set = cast(AthenaArrowResultSet, self.result_set)
219218
return result_set.as_arrow()
220219

221-
def as_polars(self) -> "pl.DataFrame":
220+
def as_polars(self) -> pl.DataFrame:
222221
"""Return query results as a Polars DataFrame.
223222
224223
Returns:

0 commit comments

Comments
 (0)