Skip to content

Commit 2bdcac8

Browse files
committed
Fix CI: linter errors, mypy types, and add httpx to test deps
- Fix ruff import sorting in __init__.py, test_sync_client.py, test_async_client.py - Fix ruff-format: async_client.py await parenthesization, string concatenation - Fix mypy: add return type to __getattr__, add type:ignore for optional httpx import - Add httpx to test dependencies so async tests work in CI - Remove redundant explicit imports from base.py shim (covered by *) https://claude.ai/code/session_01Pimg4VAco2v4srPeZj44Zm
1 parent ab6bd09 commit 2bdcac8

6 files changed

Lines changed: 28 additions & 35 deletions

File tree

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ Homepage = "https://github.com/ad-m/python-anticaptcha"
3030

3131
[project.optional-dependencies]
3232
async = ["httpx>=0.24"]
33-
tests = ["pytest", "pytest-asyncio", "retry", "selenium"]
33+
tests = ["pytest", "pytest-asyncio", "httpx>=0.24", "retry", "selenium"]
3434
docs = ["sphinx", "sphinx-rtd-theme"]
3535

3636
[tool.setuptools.package-data]

python_anticaptcha/__init__.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
import contextlib
22
from importlib.metadata import PackageNotFoundError, version
33

4-
from .sync_client import AnticaptchaClient, Job
54
from .exceptions import AnticaptchaException
65
from .proxy import Proxy
6+
from .sync_client import AnticaptchaClient, Job
77
from .tasks import (
88
AntiGateTask,
99
AntiGateTaskProxyless,
@@ -29,7 +29,7 @@
2929
__version__ = version(__name__)
3030

3131

32-
def __getattr__(name: str):
32+
def __getattr__(name: str) -> type:
3333
if name in ("AsyncAnticaptchaClient", "AsyncJob"):
3434
from .async_client import AsyncAnticaptchaClient, AsyncJob
3535

python_anticaptcha/async_client.py

Lines changed: 14 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
from urllib.parse import urljoin
88

99
try:
10-
import httpx
10+
import httpx # type: ignore[import-not-found]
1111
except ImportError:
1212
httpx = None # type: ignore[assignment]
1313

@@ -129,8 +129,7 @@ def __init__(
129129
) -> None:
130130
if httpx is None:
131131
raise ImportError(
132-
"httpx is required for async support. "
133-
"Install it with: pip install python-anticaptcha[async]"
132+
"httpx is required for async support. Install it with: pip install python-anticaptcha[async]"
134133
)
135134
self.client_key = client_key or os.environ.get("ANTICAPTCHA_API_KEY")
136135
if not self.client_key:
@@ -186,19 +185,19 @@ async def createTask(self, task: BaseTask) -> AsyncJob:
186185
"softId": self.SOFT_ID,
187186
"languagePool": self.language_pool,
188187
}
189-
response = (await self.session.post(
190-
urljoin(self.base_url, self.CREATE_TASK_URL),
191-
json=request,
192-
timeout=self.response_timeout,
193-
)).json()
188+
response = (
189+
await self.session.post(
190+
urljoin(self.base_url, self.CREATE_TASK_URL),
191+
json=request,
192+
timeout=self.response_timeout,
193+
)
194+
).json()
194195
await self._check_response(response)
195196
return AsyncJob(self, response["taskId"])
196197

197198
async def getTaskResult(self, task_id: int) -> dict[str, Any]:
198199
request = {"clientKey": self.client_key, "taskId": task_id}
199-
response = (await self.session.post(
200-
urljoin(self.base_url, self.TASK_RESULT_URL), json=request
201-
)).json()
200+
response = (await self.session.post(urljoin(self.base_url, self.TASK_RESULT_URL), json=request)).json()
202201
await self._check_response(response)
203202
return response
204203

@@ -207,33 +206,25 @@ async def getBalance(self) -> float:
207206
"clientKey": self.client_key,
208207
"softId": self.SOFT_ID,
209208
}
210-
response = (await self.session.post(
211-
urljoin(self.base_url, self.BALANCE_URL), json=request
212-
)).json()
209+
response = (await self.session.post(urljoin(self.base_url, self.BALANCE_URL), json=request)).json()
213210
await self._check_response(response)
214211
return response["balance"]
215212

216213
async def getAppStats(self, soft_id: int, mode: str) -> dict[str, Any]:
217214
request = {"clientKey": self.client_key, "softId": soft_id, "mode": mode}
218-
response = (await self.session.post(
219-
urljoin(self.base_url, self.APP_STAT_URL), json=request
220-
)).json()
215+
response = (await self.session.post(urljoin(self.base_url, self.APP_STAT_URL), json=request)).json()
221216
await self._check_response(response)
222217
return response
223218

224219
async def reportIncorrectImage(self, task_id: int) -> bool:
225220
request = {"clientKey": self.client_key, "taskId": task_id}
226-
response = (await self.session.post(
227-
urljoin(self.base_url, self.REPORT_IMAGE_URL), json=request
228-
)).json()
221+
response = (await self.session.post(urljoin(self.base_url, self.REPORT_IMAGE_URL), json=request)).json()
229222
await self._check_response(response)
230223
return bool(response.get("status", False))
231224

232225
async def reportIncorrectRecaptcha(self, task_id: int) -> bool:
233226
request = {"clientKey": self.client_key, "taskId": task_id}
234-
response = (await self.session.post(
235-
urljoin(self.base_url, self.REPORT_RECAPTCHA_URL), json=request
236-
)).json()
227+
response = (await self.session.post(urljoin(self.base_url, self.REPORT_RECAPTCHA_URL), json=request)).json()
237228
await self._check_response(response)
238229
return response["status"] == "success"
239230

python_anticaptcha/base.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,2 @@
11
# Backward compatibility — canonical location is sync_client.py
22
from .sync_client import * # noqa: F401,F403
3-
from .sync_client import Job, AnticaptchaClient

tests/test_async_client.py

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
1-
from unittest.mock import patch, MagicMock, AsyncMock
1+
from unittest.mock import AsyncMock, MagicMock, patch
2+
23
import pytest
34

45
from python_anticaptcha.async_client import (
6+
SLEEP_EVERY_CHECK_FINISHED,
57
AsyncAnticaptchaClient,
68
AsyncJob,
7-
SLEEP_EVERY_CHECK_FINISHED,
89
)
910
from python_anticaptcha.exceptions import AnticaptchaException
1011

@@ -180,11 +181,13 @@ class TestAsyncJobJoinOnCheck:
180181
@patch("python_anticaptcha.async_client.asyncio.sleep", new_callable=AsyncMock)
181182
async def test_on_check_called_each_iteration(self, mock_sleep):
182183
client = MagicMock()
183-
client.getTaskResult = AsyncMock(side_effect=[
184-
{"status": "processing"},
185-
{"status": "processing"},
186-
{"status": "ready", "solution": {}},
187-
])
184+
client.getTaskResult = AsyncMock(
185+
side_effect=[
186+
{"status": "processing"},
187+
{"status": "processing"},
188+
{"status": "ready", "solution": {}},
189+
]
190+
)
188191
job = AsyncJob(client, task_id=1)
189192
callback = MagicMock()
190193
await job.join(on_check=callback)

tests/test_sync_client.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@
22

33
import pytest
44

5-
from python_anticaptcha.sync_client import SLEEP_EVERY_CHECK_FINISHED, AnticaptchaClient, Job
65
from python_anticaptcha.exceptions import AnticaptchaException
6+
from python_anticaptcha.sync_client import SLEEP_EVERY_CHECK_FINISHED, AnticaptchaClient, Job
77

88

99
class TestAnticaptchaClientInit:

0 commit comments

Comments
 (0)