From fa941d9b5ecb5ca6cb5af48416f243f22c46909d Mon Sep 17 00:00:00 2001 From: Adam Dobrawy Date: Sat, 7 Mar 2026 14:18:55 +0100 Subject: [PATCH 1/2] Add py.typed marker and complete type annotations Add PEP 561 py.typed marker so type checkers (mypy, pyright) recognize the package as typed. Complete type annotations for all public methods missing them: context manager protocol, createTask/createTaskSmee parameter types, and exception subclass constructors. Co-Authored-By: Claude Opus 4.6 --- pyproject.toml | 3 +++ python_anticaptcha/base.py | 17 ++++++++++++----- python_anticaptcha/exceptions.py | 4 ++-- 3 files changed, 17 insertions(+), 7 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 67d0624..7906c35 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -31,6 +31,9 @@ async = ["httpx>=0.24"] tests = ["pytest", "retry", "selenium"] docs = ["sphinx"] +[tool.setuptools.package-data] +python_anticaptcha = ["py.typed"] + [tool.setuptools-scm] fallback_version = "0.0.0" diff --git a/python_anticaptcha/base.py b/python_anticaptcha/base.py index 7db0c38..05524f4 100644 --- a/python_anticaptcha/base.py +++ b/python_anticaptcha/base.py @@ -5,10 +5,12 @@ import time import json import warnings +from types import TracebackType from typing import Any from urllib.parse import urljoin from .exceptions import AnticaptchaException +from .tasks import BaseTask SLEEP_EVERY_CHECK_FINISHED = 3 MAXIMUM_JOIN_TIME = 60 * 5 @@ -111,14 +113,19 @@ def __init__( ) self.session = requests.Session() - def __enter__(self): + def __enter__(self) -> AnticaptchaClient: return self - def __exit__(self, exc_type, exc_val, exc_tb): + def __exit__( + self, + exc_type: type[BaseException] | None, + exc_val: BaseException | None, + exc_tb: TracebackType | None, + ) -> bool: self.session.close() return False - def close(self): + def close(self) -> None: self.session.close() def __repr__(self) -> str: @@ -146,7 +153,7 @@ def _check_response(self, response: dict[str, Any]) -> None: response["errorId"], response["errorCode"], response["errorDescription"] ) - def createTask(self, task: Any) -> Job: + def createTask(self, task: BaseTask) -> Job: request = { "clientKey": self.client_key, "task": task.serialize(), @@ -161,7 +168,7 @@ def createTask(self, task: Any) -> Job: self._check_response(response) return Job(self, response["taskId"]) - def createTaskSmee(self, task: Any, timeout: int = MAXIMUM_JOIN_TIME) -> Job: + def createTaskSmee(self, task: BaseTask, timeout: int = MAXIMUM_JOIN_TIME) -> Job: """ Beta method to stream response from smee.io """ diff --git a/python_anticaptcha/exceptions.py b/python_anticaptcha/exceptions.py index ffeb085..de73595 100644 --- a/python_anticaptcha/exceptions.py +++ b/python_anticaptcha/exceptions.py @@ -15,7 +15,7 @@ def __init__(self, error_id: int | str | None, error_code: int | str, error_desc class InvalidWidthException(AnticaptchaException): - def __init__(self, width): + def __init__(self, width: int) -> None: self.width = width msg = "Invalid width (%s). Can be one of these: 100, 50, 33, 25." % ( self.width, @@ -24,7 +24,7 @@ def __init__(self, width): class MissingNameException(AnticaptchaException): - def __init__(self, cls): + def __init__(self, cls: type) -> None: self.cls = cls msg = 'Missing name data in {0}. Provide {0}.__init__(name="X") or {0}.serialize(name="X")'.format( str(self.cls) From e84e3768632f8918eafd81988082fbddf7fef11f Mon Sep 17 00:00:00 2001 From: Adam Dobrawy Date: Sat, 7 Mar 2026 14:23:31 +0100 Subject: [PATCH 2/2] Exclude internal type attribute from Sphinx autodoc The task class `type` attributes conflict with the builtin `type` used in type annotations, causing an ambiguous cross-reference warning that fails the -W docs build. Co-Authored-By: Claude Opus 4.6 --- docs/conf.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/conf.py b/docs/conf.py index 229a8cf..aa39c12 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -44,6 +44,10 @@ "sphinx.ext.viewcode", ] +autodoc_default_options = { + "exclude-members": "type", +} + # Add any paths that contain templates here, relative to this directory. templates_path = ["_templates"]