Skip to content

Commit 02da113

Browse files
committed
drop python 3.9 and add doc
1 parent a15ad74 commit 02da113

6 files changed

Lines changed: 141 additions & 94 deletions

File tree

deepl/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
""".. include:: ../README.md"""
1+
""".. include:: ../README.md""" # noqa: D415
22

33
import importlib.metadata
44

deepl/deepl.py

Lines changed: 45 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,41 +1,40 @@
1-
from __future__ import annotations
1+
"""Translate text using DeepL with Playwright."""
22

33
import asyncio
44
import contextlib
55
import os
6+
from collections.abc import Coroutine
67
from functools import partial
7-
from typing import TYPE_CHECKING, Any, ClassVar
8+
from typing import Any, ClassVar
89
from urllib.parse import quote
910

1011
from install_playwright import install
1112
from playwright._impl._errors import Error as PlaywrightError
1213
from playwright.async_api import async_playwright
13-
14-
if TYPE_CHECKING:
15-
from collections.abc import Coroutine
16-
17-
from playwright.async_api._generated import Browser, Playwright
14+
from playwright.async_api._generated import Browser, Playwright
1815

1916

2017
class DeepLCLIError(Exception):
21-
pass
18+
"""Generic error for DeepLCLI."""
2219

2320

2421
class DeepLCLIPageLoadError(Exception):
25-
pass
22+
"""Page load error for DeepLCLI."""
2623

2724

2825
class DeepLCLI:
29-
"""
26+
"""Translate text using DeepL with Playwright.
27+
3028
How to get language list:
29+
3130
1. open language dropdown
3231
2. run on console:
3332
3433
```
3534
// const fr =
3635
// cost to =
3736
Array.from(
38-
document.querySelectorAll(`button[data-testid^='translator-lang-option']`)
37+
document.querySelectorAll(`button[data-testid^='translator-lang-option']`)
3938
).map(e=>e.getAttribute('data-testid').split('translator-lang-option-')[1].toLowerCase())
4039
// new Set(fr).difference(new Set(to))
4140
// new Set(to).difference(new Set(fr))
@@ -90,6 +89,17 @@ def __init__(
9089
*,
9190
use_dom_submit: bool = False,
9291
) -> None:
92+
"""Initialize DeepLCLI.
93+
94+
Args:
95+
fr_lang (str): Source language.
96+
to_lang (str): Target language.
97+
timeout (int): Timeout in milliseconds. Default is 15000ms.
98+
use_dom_submit (bool): Use DOM submit instead of URL. Default is False.
99+
100+
Raises:
101+
DeepLCLIError: If the language is not valid.
102+
"""
93103
if fr_lang not in self.fr_langs:
94104
raise DeepLCLIError(
95105
f"{fr_lang!r} is not valid language. Valid language:\n" + repr(self.fr_langs),
@@ -108,13 +118,37 @@ def __init__(
108118
self.use_dom_submit = use_dom_submit
109119

110120
def translate(self, script: str) -> str:
121+
"""Translate script.
122+
123+
Args:
124+
script (str): Script to translate.
125+
126+
Returns:
127+
str: Translated script.
128+
129+
Raises:
130+
DeepLCLIError: If the script is empty or too long.
131+
DeepLCLIPageLoadError: If the page load fails.
132+
"""
111133
script = self.__sanitize_script(script)
112134

113135
# run in the current thread
114136
loop = asyncio.get_event_loop()
115137
return loop.run_until_complete(self.__translate(script))
116138

117139
def translate_async(self, script: str) -> Coroutine[Any, Any, str]:
140+
"""Translate script asynchronously.
141+
142+
Args:
143+
script (str): Script to translate.
144+
145+
Returns:
146+
Coroutine[Any, Any, str]: Translated script.
147+
148+
Raises:
149+
DeepLCLIError: If the script is empty or too long.
150+
DeepLCLIPageLoadError: If the page load fails.
151+
"""
118152
script = self.__sanitize_script(script)
119153

120154
return self.__translate(script)

deepl/main.py

Lines changed: 71 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
from __future__ import annotations
1+
"""Main module of deepl CLI."""
22

33
import argparse
44
import sys
@@ -14,12 +14,23 @@
1414

1515

1616
class DeepLCLIFormatter(
17-
argparse.ArgumentDefaultsHelpFormatter, argparse.RawDescriptionHelpFormatter,
17+
argparse.ArgumentDefaultsHelpFormatter,
18+
argparse.RawDescriptionHelpFormatter,
1819
):
19-
pass
20+
"""Custom help formatter for argparse."""
2021

2122

2223
def check_file(v: str) -> str:
24+
"""Check if the file is a text file.
25+
26+
Args:
27+
v (str): file path
28+
Returns:
29+
str: file path
30+
Raises:
31+
argparse.ArgumentTypeError: if the file is not a text file
32+
"""
33+
2334
def is_binary_string(b: bytes) -> bool:
2435
chars = bytearray({7, 8, 9, 10, 12, 13, 27} | set(range(0x20, 0x100)) - {0x7F})
2536
return bool(b.translate(None, chars))
@@ -37,6 +48,15 @@ def is_binary_string(b: bytes) -> bool:
3748

3849

3950
def check_natural(v: str) -> int:
51+
"""Check if the value is a natural number.
52+
53+
Args:
54+
v (str): value to check
55+
Returns:
56+
int: value
57+
Raises:
58+
argparse.ArgumentTypeError: if the value is not a natural number
59+
"""
4060
n = int(v)
4161
if n < 0:
4262
msg = f"{v} must not be negative."
@@ -46,26 +66,50 @@ def check_natural(v: str) -> int:
4666

4767

4868
def check_input_lang(lang: str) -> str:
69+
"""Check if the input language is valid.
70+
71+
Args:
72+
lang (str): input language
73+
Returns:
74+
str: input language
75+
Raises:
76+
argparse.ArgumentTypeError: if the input language is not valid
77+
"""
4978
if lang not in DeepLCLI.fr_langs:
5079
raise argparse.ArgumentTypeError(
51-
f"{lang!r} is not valid language. Valid language:\n"
52-
+ repr(DeepLCLI.fr_langs),
80+
f"{lang!r} is not valid language. Valid language:\n" + repr(DeepLCLI.fr_langs),
5381
)
5482

5583
return lang
5684

5785

5886
def check_output_lang(lang: str) -> str:
87+
"""Check if the output language is valid.
88+
89+
Args:
90+
lang (str): output language
91+
Returns:
92+
str: output language
93+
Raises:
94+
argparse.ArgumentTypeError: if the output language is not valid
95+
"""
5996
if lang not in DeepLCLI.to_langs:
6097
raise argparse.ArgumentTypeError(
61-
f"{lang!r} is not valid language. Valid language:\n"
62-
+ repr(DeepLCLI.to_langs),
98+
f"{lang!r} is not valid language. Valid language:\n" + repr(DeepLCLI.to_langs),
6399
)
64100
return lang
65101

66102

67103
def parse_args(test: str | None = None) -> argparse.Namespace:
68-
"""Parse arguments."""
104+
"""Parse arguments.
105+
106+
Args:
107+
test (str | None): test string
108+
Returns:
109+
argparse.Namespace: parsed arguments
110+
Raises:
111+
argparse.ArgumentTypeError: if the arguments are not valid
112+
"""
69113
parser = argparse.ArgumentParser(
70114
prog="deepl",
71115
formatter_class=(
@@ -98,10 +142,18 @@ def parse_args(test: str | None = None) -> argparse.Namespace:
98142
help="read source text from stdin",
99143
)
100144
parser.add_argument(
101-
"-F", "--fr", type=check_input_lang, help="input language", required=True,
145+
"-F",
146+
"--fr",
147+
type=check_input_lang,
148+
help="input language",
149+
required=True,
102150
)
103151
parser.add_argument(
104-
"-T", "--to", type=check_output_lang, help="output language", required=True,
152+
"-T",
153+
"--to",
154+
type=check_output_lang,
155+
help="output language",
156+
required=True,
105157
)
106158
parser.add_argument(
107159
"-t",
@@ -118,7 +170,10 @@ def parse_args(test: str | None = None) -> argparse.Namespace:
118170
help="make output verbose",
119171
)
120172
parser.add_argument(
121-
"-V", "--version", action="version", version=f"%(prog)s {__version__}",
173+
"-V",
174+
"--version",
175+
action="version",
176+
version=f"%(prog)s {__version__}",
122177
)
123178

124179
if test is None:
@@ -127,6 +182,11 @@ def parse_args(test: str | None = None) -> argparse.Namespace:
127182

128183

129184
def main(test: str | None = None) -> None:
185+
"""Main function.
186+
187+
Args:
188+
test (str | None): test string
189+
"""
130190
args = parse_args(test)
131191
t = DeepLCLI(args.fr, args.to, timeout=args.timeout)
132192
script = ""

examples/async.py

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

88

99
def print_translated_text(future: asyncio.Future[str]) -> None:
10-
"""receive the result of async func and print."""
10+
"""Receive the result of async func and print."""
1111
try:
1212
translated_text = future.result()
1313
print(translated_text)
@@ -19,13 +19,13 @@ def print_translated_text(future: asyncio.Future[str]) -> None:
1919

2020

2121
async def translate(text: str) -> str:
22-
"""translate asynchronously."""
22+
"""Translate asynchronously."""
2323
t = DeepLCLI("en", "ja")
2424
return await t.translate_async(text)
2525

2626

2727
async def do_something() -> None:
28-
"""do something asynchronously."""
28+
"""Do something asynchronously."""
2929
await asyncio.sleep(10)
3030
print("Another task done!")
3131

pyproject.toml

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,10 @@ keywords = [
1313
]
1414
license = { text = "MIT" }
1515
authors = [ { name = "eggplants", email = "w10776e8w@yahoo.co.jp" } ]
16-
requires-python = ">=3.9,<4"
16+
requires-python = ">=3.10,<4"
1717
classifiers = [
1818
"License :: OSI Approved :: MIT License",
1919
"Programming Language :: Python :: 3 :: Only",
20-
"Programming Language :: Python :: 3.9",
2120
"Programming Language :: Python :: 3.10",
2221
"Programming Language :: Python :: 3.11",
2322
"Programming Language :: Python :: 3.12",
@@ -36,7 +35,7 @@ scripts.deepl = "deepl.main:main"
3635

3736
[dependency-groups]
3837
dev = [
39-
"mypy>=0.991,<1.15",
38+
"mypy>=1,<1.15",
4039
"pre-commit>=2.20,<4",
4140
"pytest>=7.2.2,<9",
4241
"pytest-asyncio>=0.21,<0.25",
@@ -63,24 +62,23 @@ format.quote-style = "double"
6362
lint.select = [
6463
"ALL",
6564
]
66-
lint.ignore = [
67-
"D",
68-
]
6965
lint.per-file-ignores."examples/*.py" = [
66+
"D",
7067
"INP001", # Add an __init__.py.
7168
"T201", # `print` found
7269
]
7370
lint.per-file-ignores."main.py" = [
7471
"T201", # `print` found
7572
]
76-
lint.per-file-ignores."tests/test_*.py" = [
73+
lint.per-file-ignores."tests/*.py" = [
74+
"D",
7775
"S101", # Use of assert detected
7876
]
7977
lint.pydocstyle.convention = "google"
8078

8179
[tool.mypy]
8280
pretty = true
83-
python_version = "3.9"
81+
python_version = "3.10"
8482
show_error_codes = true
8583
strict = true
8684

0 commit comments

Comments
 (0)