Skip to content

Commit 2a0d4fb

Browse files
authored
feat!: drop support for Python 3.9 (#411)
* feat!: drop support for Python 3.9 Signed-off-by: Luka Peschke <luka.peschke@toucantoco.com> * chore: make format Signed-off-by: Luka Peschke <luka.peschke@toucantoco.com> * adapt github actions Signed-off-by: Luka Peschke <luka.peschke@toucantoco.com> * fix(ci): set up python in check-wheel-build job Signed-off-by: Luka Peschke <luka.peschke@toucantoco.com> --------- Signed-off-by: Luka Peschke <luka.peschke@toucantoco.com>
1 parent 9a02e92 commit 2a0d4fb

File tree

8 files changed

+54
-210
lines changed

8 files changed

+54
-210
lines changed

.github/workflows/CI.yml

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ on:
88
types: [opened, synchronize, reopened]
99

1010
env:
11-
MIN_PYTHON_VERSION: "3.9"
11+
MIN_PYTHON_VERSION: "3.10"
1212

1313
defaults:
1414
run:
@@ -61,7 +61,7 @@ jobs:
6161
runs-on: ${{ matrix.os }}
6262
strategy:
6363
matrix:
64-
python-version: ["3.9", "3.10", "3.11", "3.12", "3.13", "3.14"]
64+
python-version: ["3.10", "3.11", "3.12", "3.13", "3.14"]
6565
os: ["ubuntu-latest", "macos-14", "windows-latest"]
6666
steps:
6767
- uses: actions/checkout@v5
@@ -86,7 +86,7 @@ jobs:
8686
matrix:
8787
# Only testing the build on the smallest supported Python version
8888
# since we're building abi3 wheels
89-
python-version: ["3.9"]
89+
python-version: ["3.10"]
9090
os: ["ubuntu-latest", "macos-14", "windows-latest"]
9191
architecture: [x86-64, aarch64]
9292
exclude:
@@ -101,7 +101,10 @@ jobs:
101101
run: |
102102
TARGET=${{ matrix.os == 'macos-14' && (matrix.architecture == 'aarch64' && 'aarch64-apple-darwin' || 'x86_64-apple-darwin') || (matrix.architecture == 'aarch64' && 'aarch64-unknown-linux-gnu' || null) }}
103103
echo "target=$TARGET" >> $GITHUB_OUTPUT
104-
104+
- name: Set up Python
105+
uses: actions/setup-python@v6
106+
with:
107+
python-version: ${{ matrix.python-version }}
105108
- name: build (fast)
106109
uses: PyO3/maturin-action@v1
107110
with:

.github/workflows/release.yml

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ jobs:
1111
runs-on: ubuntu-latest
1212
strategy:
1313
matrix:
14-
python-version: ["3.9"]
14+
python-version: ["3.10"]
1515
architecture: [x86-64, aarch64]
1616
steps:
1717
- uses: actions/checkout@v5
@@ -33,7 +33,7 @@ jobs:
3333
runs-on: macos-14
3434
strategy:
3535
matrix:
36-
python-version: ["3.9"]
36+
python-version: ["3.10"]
3737
architecture: [x86-64, aarch64]
3838
steps:
3939
- uses: actions/checkout@v5
@@ -55,7 +55,7 @@ jobs:
5555
strategy:
5656
matrix:
5757
# amd64 only for windows, as no arm64 runners are available
58-
python-version: ["3.9"]
58+
python-version: ["3.10"]
5959
steps:
6060
- uses: actions/checkout@v5
6161
- uses: dtolnay/rust-toolchain@stable
@@ -102,34 +102,34 @@ jobs:
102102
- uses: rust-lang/crates-io-auth-action@v1
103103
id: auth
104104

105-
- name: Download Linux 3.9 wheels for x86-64
105+
- name: Download Linux 3.10 wheels for x86-64
106106
uses: actions/download-artifact@v6
107107
with:
108-
name: "wheels-linux-python-3.9-x86-64"
108+
name: "wheels-linux-python-3.10-x86-64"
109109
path: wheels-linux
110110

111-
- name: Download Linux 3.9 wheels for aarch64
111+
- name: Download Linux 3.10 wheels for aarch64
112112
uses: actions/download-artifact@v6
113113
with:
114-
name: "wheels-linux-python-3.9-aarch64"
114+
name: "wheels-linux-python-3.10-aarch64"
115115
path: wheels-linux
116116

117-
- name: Download MacOS 3.9 wheels for x86-64
117+
- name: Download MacOS 3.10 wheels for x86-64
118118
uses: actions/download-artifact@v6
119119
with:
120-
name: "wheels-macos-python-3.9-x86-64"
120+
name: "wheels-macos-python-3.10-x86-64"
121121
path: wheels-macos
122122

123-
- name: Download MacOS 3.9 wheels for aarch64
123+
- name: Download MacOS 3.10 wheels for aarch64
124124
uses: actions/download-artifact@v6
125125
with:
126-
name: "wheels-macos-python-3.9-aarch64"
126+
name: "wheels-macos-python-3.10-aarch64"
127127
path: wheels-macos
128128

129-
- name: Download Windows 3.9 wheels
129+
- name: Download Windows 3.10 wheels
130130
uses: actions/download-artifact@v6
131131
with:
132-
name: "wheels-windows-python-3.9"
132+
name: "wheels-windows-python-3.10"
133133
path: wheels-windows
134134

135135
- name: Download sdist

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ polars-core = { version = ">=0.50", default-features = false, features = [
3737
"dtype-datetime",
3838
"dtype-duration",
3939
], optional = true }
40-
pyo3 = { version = "^0.26", features = ["abi3-py39"], optional = true }
40+
pyo3 = { version = "^0.26", features = ["abi3-py310"], optional = true }
4141
pyo3-arrow = { version = "^0.14", default-features = false, optional = true }
4242
pyo3-log = { version = "^0.13.2", optional = true }
4343

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,7 @@ df = pl.DataFrame(table) # Zero-copy via PyCapsule, no pyarrow needed
104104

105105
You'll need:
106106
1. **[Rust](https://rustup.rs/)** - Rust stable or nightly
107-
2. **[uv](https://docs.astral.sh/uv/getting-started/installation/)** - Fast Python package manager (will install Python 3.9+ automatically)
107+
2. **[uv](https://docs.astral.sh/uv/getting-started/installation/)** - Fast Python package manager (will install Python 3.10+ automatically)
108108
3. **[git](https://git-scm.com/)** - For version control
109109
4. **[make](https://www.gnu.org/software/make/)** - For running development commands
110110

pyproject.toml

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ name = "fastexcel"
77
description = "A fast excel file reader for Python, written in Rust"
88
readme = "README.md"
99
license = { file = "LICENSE" }
10-
requires-python = ">=3.9"
10+
requires-python = ">=3.10"
1111
classifiers = [
1212
"Development Status :: 5 - Production/Stable",
1313
"License :: OSI Approved :: MIT License",
@@ -16,7 +16,6 @@ classifiers = [
1616
"Programming Language :: Python",
1717
"Programming Language :: Python :: 3",
1818
"Programming Language :: Python :: 3 :: Only",
19-
"Programming Language :: Python :: 3.9",
2019
"Programming Language :: Python :: 3.10",
2120
"Programming Language :: Python :: 3.11",
2221
"Programming Language :: Python :: 3.12",
@@ -68,7 +67,7 @@ module-name = "fastexcel._fastexcel"
6867
features = ["__maturin"]
6968

7069
[tool.mypy]
71-
python_version = "3.9"
70+
python_version = "3.10"
7271
follow_imports = "silent"
7372
ignore_missing_imports = true
7473
# A few custom options
@@ -84,11 +83,11 @@ log_cli_level = "INFO"
8483

8584
[tool.ruff]
8685
line-length = 100
87-
target-version = "py39"
86+
target-version = "py310"
8887

8988
[tool.ruff.lint]
9089
# Enable Pyflakes `E` and `F` codes by default.
91-
select = ["E", "F", "I", "Q", "FA102"]
90+
select = ["E", "F", "I", "Q", "FA102", "UP"]
9291

9392
[tool.uv]
9493
# this ensures that `uv run` doesn't actually build the package; a `make`

python/fastexcel/__init__.py

Lines changed: 15 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,8 @@
11
from __future__ import annotations
22

3-
import sys
43
import typing
5-
from typing import TYPE_CHECKING, Callable, Literal
6-
7-
if sys.version_info < (3, 10):
8-
from typing_extensions import TypeAlias
9-
else:
10-
from typing import TypeAlias
4+
from collections.abc import Callable
5+
from typing import TYPE_CHECKING, Literal, TypeAlias
116

127
if TYPE_CHECKING:
138
import pandas as pd
@@ -101,7 +96,7 @@ def visible(self) -> SheetVisible:
10196
"""The visibility of the sheet"""
10297
return self._sheet.visible
10398

104-
def to_arrow(self) -> "pa.RecordBatch":
99+
def to_arrow(self) -> pa.RecordBatch:
105100
"""Converts the sheet to a pyarrow `RecordBatch`
106101
107102
Requires the `pyarrow` extra to be installed.
@@ -112,7 +107,7 @@ def to_arrow(self) -> "pa.RecordBatch":
112107
)
113108
return self._sheet.to_arrow()
114109

115-
def to_arrow_with_errors(self) -> "tuple[pa.RecordBatch, CellErrors | None]":
110+
def to_arrow_with_errors(self) -> tuple[pa.RecordBatch, CellErrors | None]:
116111
"""Converts the sheet to a pyarrow `RecordBatch` with error information.
117112
118113
Stores the positions of any values that cannot be parsed as the specified type and were
@@ -129,7 +124,7 @@ def to_arrow_with_errors(self) -> "tuple[pa.RecordBatch, CellErrors | None]":
129124
return (rb, None)
130125
return (rb, cell_errors)
131126

132-
def to_pandas(self) -> "pd.DataFrame":
127+
def to_pandas(self) -> pd.DataFrame:
133128
"""Converts the sheet to a Pandas `DataFrame`.
134129
135130
Requires the `pandas` extra to be installed.
@@ -139,7 +134,7 @@ def to_pandas(self) -> "pd.DataFrame":
139134
# (see https://pandas.pydata.org/docs/reference/api/pandas.api.interchange.from_dataframe.html)
140135
return self.to_arrow().to_pandas()
141136

142-
def to_polars(self) -> "pl.DataFrame":
137+
def to_polars(self) -> pl.DataFrame:
143138
"""Converts the sheet to a Polars `DataFrame`.
144139
145140
Uses the Arrow PyCapsule Interface for zero-copy data exchange.
@@ -225,7 +220,7 @@ def specified_dtypes(self) -> DTypeMap | None:
225220
"""The dtypes specified for the table"""
226221
return self._table.specified_dtypes
227222

228-
def to_arrow(self) -> "pa.RecordBatch":
223+
def to_arrow(self) -> pa.RecordBatch:
229224
"""Converts the table to a pyarrow `RecordBatch`
230225
231226
Requires the `pyarrow` extra to be installed.
@@ -236,7 +231,7 @@ def to_arrow(self) -> "pa.RecordBatch":
236231
)
237232
return self._table.to_arrow()
238233

239-
def to_pandas(self) -> "pd.DataFrame":
234+
def to_pandas(self) -> pd.DataFrame:
240235
"""Converts the table to a Pandas `DataFrame`.
241236
242237
Requires the `pandas` extra to be installed.
@@ -246,7 +241,7 @@ def to_pandas(self) -> "pd.DataFrame":
246241
# (see https://pandas.pydata.org/docs/reference/api/pandas.api.interchange.from_dataframe.html)
247242
return self.to_arrow().to_pandas()
248243

249-
def to_polars(self) -> "pl.DataFrame":
244+
def to_polars(self) -> pl.DataFrame:
250245
"""Converts the table to a Polars `DataFrame`.
251246
252247
Uses the Arrow PyCapsule Interface for zero-copy data exchange.
@@ -328,7 +323,7 @@ def load_sheet(
328323
| None = None,
329324
dtypes: DType | DTypeMap | None = None,
330325
eager: Literal[True] = ...,
331-
) -> "pa.RecordBatch": ...
326+
) -> pa.RecordBatch: ...
332327

333328
def load_sheet(
334329
self,
@@ -347,7 +342,7 @@ def load_sheet(
347342
| None = None,
348343
dtypes: DType | DTypeMap | None = None,
349344
eager: bool = False,
350-
) -> "ExcelSheet | pa.RecordBatch":
345+
) -> ExcelSheet | pa.RecordBatch:
351346
"""Loads a sheet by index or name.
352347
353348
:param idx_or_name: The index (starting at 0) or the name of the sheet to load.
@@ -469,7 +464,7 @@ def load_table(
469464
| None = None,
470465
dtypes: DType | DTypeMap | None = None,
471466
eager: Literal[True] = ...,
472-
) -> "pa.RecordBatch": ...
467+
) -> pa.RecordBatch: ...
473468

474469
def load_table(
475470
self,
@@ -488,7 +483,7 @@ def load_table(
488483
| None = None,
489484
dtypes: DType | DTypeMap | None = None,
490485
eager: bool = False,
491-
) -> "ExcelTable | pa.RecordBatch":
486+
) -> ExcelTable | pa.RecordBatch:
492487
"""Loads a table by name.
493488
494489
:param name: The name of the table to load.
@@ -574,7 +569,7 @@ def load_sheet_eager(
574569
dtype_coercion: Literal["coerce", "strict"] = "coerce",
575570
use_columns: list[str] | list[int] | str | None = None,
576571
dtypes: DType | DTypeMap | None = None,
577-
) -> "pa.RecordBatch":
572+
) -> pa.RecordBatch:
578573
"""Loads a sheet eagerly by index or name.
579574
580575
For xlsx files, this will be faster and more memory-efficient, as it will use
@@ -672,7 +667,7 @@ def read_excel(source: Path | str | bytes) -> ExcelReader:
672667
673668
:param source: The path to a file or its content as bytes
674669
"""
675-
if isinstance(source, (str, Path)):
670+
if isinstance(source, str | Path):
676671
source = expanduser(source)
677672
return ExcelReader(_read_excel(source))
678673

python/fastexcel/_fastexcel.pyi

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
from __future__ import annotations
22

33
import typing
4-
from typing import TYPE_CHECKING, Callable, Literal
4+
from collections.abc import Callable
5+
from typing import TYPE_CHECKING, Literal
56

67
if TYPE_CHECKING:
78
import pyarrow as pa
@@ -89,12 +90,12 @@ class _ExcelSheet:
8990
@property
9091
def visible(self) -> SheetVisible:
9192
"""The visibility of the sheet"""
92-
def to_arrow(self) -> "pa.RecordBatch":
93+
def to_arrow(self) -> pa.RecordBatch:
9394
"""Converts the sheet to a pyarrow `RecordBatch`
9495
9596
Requires the `pyarrow` extra to be installed.
9697
"""
97-
def to_arrow_with_errors(self) -> "tuple[pa.RecordBatch, CellErrors]":
98+
def to_arrow_with_errors(self) -> tuple[pa.RecordBatch, CellErrors]:
9899
"""Converts the sheet to a pyarrow `RecordBatch` with error information.
99100
100101
Stores the positions of any values that cannot be parsed as the specified type and were
@@ -148,7 +149,7 @@ class _ExcelTable:
148149
@property
149150
def specified_dtypes(self) -> DTypeMap | None:
150151
"""The dtypes specified for the table"""
151-
def to_arrow(self) -> "pa.RecordBatch":
152+
def to_arrow(self) -> pa.RecordBatch:
152153
"""Converts the table to a pyarrow `RecordBatch`
153154
154155
Requires the `pyarrow` extra to be installed.

0 commit comments

Comments
 (0)