Skip to content

Commit 0fb6f41

Browse files
Upgrade minimum Python requirement to 3.10 (#8)
* Upgrade minimum Python requirement to 3.10 - Update pyproject.toml and pixi.toml to require Python 3.10+ - Modernize type hints to use built-in generics (list[T], dict[K,V], X | None) - Replace Optional, List, Dict, Tuple, Union imports with modern syntax - Implement pattern matching in file handling and action mapping - Update GitHub Actions to test only Python 3.10, 3.11, 3.12 - Remove unused typing imports - All tests pass and code quality checks pass 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <[email protected]> * Fix code formatting 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <[email protected]> --------- Co-authored-by: Claude <[email protected]>
1 parent 86379cf commit 0fb6f41

File tree

12 files changed

+163
-158
lines changed

12 files changed

+163
-158
lines changed

.github/workflows/ci.yml

Lines changed: 3 additions & 3 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.8', '3.9', '3.10', '3.11', '3.12']
14+
python-version: ['3.10', '3.11', '3.12']
1515

1616
steps:
1717
- uses: actions/checkout@v4
@@ -35,7 +35,7 @@ jobs:
3535
pip install -e ".[dev]"
3636
3737
- name: Run linting with ruff
38-
if: matrix.python-version == '3.8'
38+
if: matrix.python-version == '3.10'
3939
run: |
4040
python -m ruff check .
4141
python -m ruff format --check .
@@ -103,7 +103,7 @@ jobs:
103103
- name: Set up Python
104104
uses: actions/setup-python@v5
105105
with:
106-
python-version: '3.11'
106+
python-version: '3.12'
107107

108108
- name: Install build dependencies
109109
run: |

.github/workflows/release.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ jobs:
1414
- name: Set up Python
1515
uses: actions/setup-python@v5
1616
with:
17-
python-version: '3.11'
17+
python-version: '3.12'
1818

1919
- name: Install dependencies
2020
run: |

pixi.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ channels = ["conda-forge"]
44
platforms = ["osx-arm64", "osx-64", "linux-64", "win-64"]
55

66
[dependencies]
7-
python = ">=3.8,<3.13"
7+
python = ">=3.10,<3.13"
88
requests = ">=2.25.0,<3.0.0"
99

1010
[feature.dev.dependencies]

pyproject.toml

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ name = "nutrient-dws"
1313
version = "1.0.0"
1414
description = "Python client library for Nutrient Document Web Services API"
1515
readme = "README.md"
16-
requires-python = ">=3.8"
16+
requires-python = ">=3.10"
1717
license = {text = "MIT"}
1818
authors = [
1919
{name = "Nutrient", email = "[email protected]"},
@@ -25,8 +25,6 @@ classifiers = [
2525
"License :: OSI Approved :: MIT License",
2626
"Operating System :: OS Independent",
2727
"Programming Language :: Python :: 3",
28-
"Programming Language :: Python :: 3.8",
29-
"Programming Language :: Python :: 3.9",
3028
"Programming Language :: Python :: 3.10",
3129
"Programming Language :: Python :: 3.11",
3230
"Programming Language :: Python :: 3.12",
@@ -62,7 +60,7 @@ Repository = "https://github.com/jdrhyne/nutrient-dws-client-python"
6260
nutrient_dws = ["py.typed"]
6361

6462
[tool.ruff]
65-
target-version = "py38"
63+
target-version = "py310"
6664
line-length = 100
6765

6866
[tool.ruff.lint]
@@ -93,7 +91,7 @@ convention = "google"
9391
"tests/*" = ["D", "S101"] # Don't require docstrings in tests, allow asserts
9492

9593
[tool.mypy]
96-
python_version = "3.8"
94+
python_version = "3.10"
9795
strict = true
9896
warn_return_any = true
9997
warn_unused_ignores = false

scripts/generate_api_methods.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33

44
import re
55
from pathlib import Path
6-
from typing import Any, Dict, List
6+
from typing import Any
77

88

99
def to_snake_case(name: str) -> str:
@@ -15,7 +15,7 @@ def to_snake_case(name: str) -> str:
1515
return name
1616

1717

18-
def get_python_type(schema: Dict[str, Any]) -> str:
18+
def get_python_type(schema: dict[str, Any]) -> str:
1919
"""Convert OpenAPI schema type to Python type hint."""
2020
if not schema:
2121
return "Any"
@@ -33,7 +33,7 @@ def get_python_type(schema: Dict[str, Any]) -> str:
3333
return type_mapping.get(schema_type, "Any")
3434

3535

36-
def create_manual_tools() -> List[Dict[str, Any]]:
36+
def create_manual_tools() -> list[dict[str, Any]]:
3737
"""Create tool definitions based on the specification documentation.
3838
3939
Since the Nutrient API uses a build endpoint with actions rather than
@@ -218,7 +218,7 @@ def create_manual_tools() -> List[Dict[str, Any]]:
218218
return tools
219219

220220

221-
def generate_method_code(tool_info: Dict[str, Any]) -> str:
221+
def generate_method_code(tool_info: dict[str, Any]) -> str:
222222
"""Generate Python method code for a tool."""
223223
method_name = tool_info["method_name"]
224224
tool_name = tool_info["tool_name"]

src/nutrient_dws/api/direct.py

Lines changed: 30 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
for supported document processing operations.
55
"""
66

7-
from typing import TYPE_CHECKING, Any, Dict, List, Optional, Protocol
7+
from typing import TYPE_CHECKING, Any, Protocol
88

99
from nutrient_dws.file_handler import FileInput
1010

@@ -40,17 +40,17 @@ def _process_file(
4040
self,
4141
tool: str,
4242
input_file: FileInput,
43-
output_path: Optional[str] = None,
43+
output_path: str | None = None,
4444
**options: Any,
45-
) -> Optional[bytes]:
45+
) -> bytes | None:
4646
"""Process file method that will be provided by NutrientClient."""
4747
raise NotImplementedError("This method is provided by NutrientClient")
4848

4949
def convert_to_pdf(
5050
self,
5151
input_file: FileInput,
52-
output_path: Optional[str] = None,
53-
) -> Optional[bytes]:
52+
output_path: str | None = None,
53+
) -> bytes | None:
5454
"""Convert a document to PDF.
5555
5656
Converts Office documents (DOCX, XLSX, PPTX) to PDF format.
@@ -76,8 +76,8 @@ def convert_to_pdf(
7676
return self.build(input_file).execute(output_path) # type: ignore[attr-defined,no-any-return]
7777

7878
def flatten_annotations(
79-
self, input_file: FileInput, output_path: Optional[str] = None
80-
) -> Optional[bytes]:
79+
self, input_file: FileInput, output_path: str | None = None
80+
) -> bytes | None:
8181
"""Flatten annotations and form fields in a PDF.
8282
8383
Converts all annotations and form fields into static page content.
@@ -99,10 +99,10 @@ def flatten_annotations(
9999
def rotate_pages(
100100
self,
101101
input_file: FileInput,
102-
output_path: Optional[str] = None,
102+
output_path: str | None = None,
103103
degrees: int = 0,
104-
page_indexes: Optional[List[int]] = None,
105-
) -> Optional[bytes]:
104+
page_indexes: list[int] | None = None,
105+
) -> bytes | None:
106106
"""Rotate pages in a PDF.
107107
108108
Rotate all pages or specific pages by the specified degrees.
@@ -129,9 +129,9 @@ def rotate_pages(
129129
def ocr_pdf(
130130
self,
131131
input_file: FileInput,
132-
output_path: Optional[str] = None,
132+
output_path: str | None = None,
133133
language: str = "english",
134-
) -> Optional[bytes]:
134+
) -> bytes | None:
135135
"""Apply OCR to a PDF to make it searchable.
136136
137137
Performs optical character recognition on the PDF to extract text
@@ -156,14 +156,14 @@ def ocr_pdf(
156156
def watermark_pdf(
157157
self,
158158
input_file: FileInput,
159-
output_path: Optional[str] = None,
160-
text: Optional[str] = None,
161-
image_url: Optional[str] = None,
159+
output_path: str | None = None,
160+
text: str | None = None,
161+
image_url: str | None = None,
162162
width: int = 200,
163163
height: int = 100,
164164
opacity: float = 1.0,
165165
position: str = "center",
166-
) -> Optional[bytes]:
166+
) -> bytes | None:
167167
"""Add a watermark to a PDF.
168168
169169
Adds a text or image watermark to all pages of the PDF.
@@ -209,8 +209,8 @@ def watermark_pdf(
209209
def apply_redactions(
210210
self,
211211
input_file: FileInput,
212-
output_path: Optional[str] = None,
213-
) -> Optional[bytes]:
212+
output_path: str | None = None,
213+
) -> bytes | None:
214214
"""Apply redaction annotations to permanently remove content.
215215
216216
Applies any redaction annotations in the PDF to permanently remove
@@ -233,9 +233,9 @@ def apply_redactions(
233233
def split_pdf(
234234
self,
235235
input_file: FileInput,
236-
page_ranges: Optional[List[Dict[str, int]]] = None,
237-
output_paths: Optional[List[str]] = None,
238-
) -> List[bytes]:
236+
page_ranges: list[dict[str, int]] | None = None,
237+
output_paths: list[str] | None = None,
238+
) -> list[bytes]:
239239
"""Split a PDF into multiple documents by page ranges.
240240
241241
Splits a PDF into multiple files based on specified page ranges.
@@ -320,9 +320,9 @@ def split_pdf(
320320
def duplicate_pdf_pages(
321321
self,
322322
input_file: FileInput,
323-
page_indexes: List[int],
324-
output_path: Optional[str] = None,
325-
) -> Optional[bytes]:
323+
page_indexes: list[int],
324+
output_path: str | None = None,
325+
) -> bytes | None:
326326
"""Duplicate specific pages within a PDF document.
327327
328328
Creates a new PDF containing the specified pages in the order provided.
@@ -404,9 +404,9 @@ def duplicate_pdf_pages(
404404
def delete_pdf_pages(
405405
self,
406406
input_file: FileInput,
407-
page_indexes: List[int],
408-
output_path: Optional[str] = None,
409-
) -> Optional[bytes]:
407+
page_indexes: list[int],
408+
output_path: str | None = None,
409+
) -> bytes | None:
410410
"""Delete specific pages from a PDF document.
411411
412412
Creates a new PDF with the specified pages removed. The API approach
@@ -544,9 +544,9 @@ def delete_pdf_pages(
544544

545545
def merge_pdfs(
546546
self,
547-
input_files: List[FileInput],
548-
output_path: Optional[str] = None,
549-
) -> Optional[bytes]:
547+
input_files: list[FileInput],
548+
output_path: str | None = None,
549+
) -> bytes | None:
550550
"""Merge multiple PDF files into one.
551551
552552
Combines multiple files into a single PDF in the order provided.

0 commit comments

Comments
 (0)