From 17e0020d031cd4512e108351c46691ffc8c892f8 Mon Sep 17 00:00:00 2001 From: Adam Dobrawy Date: Sat, 7 Mar 2026 14:49:55 +0100 Subject: [PATCH 1/3] Fix obsolete and invalid documentation across the project MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Update outdated references (setup.py → pyproject.toml, TravisCI → GitHub Actions), fix broken example file links, correct typos and grammar in README and Sphinx docs, update copyright year range, fix geckodriver/chromedriver naming confusion in Makefile, update contact email in CODE_OF_CONDUCT.md, and add comprehensive changelog entries for all changes since 1.0.0. Co-Authored-By: Claude Opus 4.6 --- CHANGELOG.rst | 37 +++++++++++++++++++++++++++++++++++++ CODE_OF_CONDUCT.md | 2 +- Makefile | 12 ++++++------ README.md | 17 ++++++++--------- docs/conf.py | 12 +++++------- docs/development.rst | 10 +++++----- docs/index.rst | 2 +- docs/usage.rst | 13 ++++++------- 8 files changed, 69 insertions(+), 36 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 11f2691..08d913d 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -1,6 +1,43 @@ Changelog ========= +Unreleased +---------- + +Added +##### + +- Add context manager support to ``AnticaptchaClient`` (``__enter__``, ``__exit__``, ``close``) +- Add ``ANTICAPTCHA_API_KEY`` environment variable fallback for ``AnticaptchaClient`` +- Add ``Proxy`` frozen dataclass with ``parse_url()`` and ``to_kwargs()`` methods +- Add snake_case aliases: ``create_task``, ``create_task_smee``, ``get_balance``, ``get_app_stats`` +- Add ``py.typed`` marker and complete type annotations (`#124 `_) +- Add ``__repr__`` to ``Job``, ``AnticaptchaClient``, and ``BaseTask`` (`#123 `_) +- Add optional ``on_check`` callback to ``Job.join()`` (`#125 `_) +- ``ImageToTextTask`` now accepts file paths (``str``/``Path``), raw bytes, or file-like objects + +Changed +####### + +- **Breaking:** Minimum Python version increased from 2.7+ to 3.9+ +- Migrate from ``setup.py`` / ``setup.cfg`` to ``pyproject.toml`` (PEP 621) (`#122 `_) +- Switch README from RST to Markdown (`#126 `_) +- Switch test runner from nose2 to pytest +- Fix ``RecaptchaV2EnterpriseTask`` missing proxyless base class inheritance +- Fix ``ImageToTextTask.serialize()`` sending ``None`` values +- Fix ``GeeTestTask`` incorrect inheritance +- Fix ``AntiGateTaskProxyless`` super() call +- Remove redundant cookies serialization in ``ProxyMixin`` +- Use Python 3 ``super()`` without arguments throughout codebase + +Removed +####### + +- Drop Python 2.7 and Python 3.4-3.8 support +- Remove ``six`` dependency (replaced with stdlib ``urllib.parse``) +- Remove ``compat.py`` module +- Remove legacy ``setup.py`` and ``setup.cfg`` + 1.0.0 - 2022-03-28 ------------------ diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md index fe881b9..51a77f3 100644 --- a/CODE_OF_CONDUCT.md +++ b/CODE_OF_CONDUCT.md @@ -34,7 +34,7 @@ This Code of Conduct applies both within project spaces and in public spaces whe ## Enforcement -Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at naczelnik@jawnosc.tk. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately. +Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at naczelnik@jawne.info.pl. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately. Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership. diff --git a/Makefile b/Makefile index d85d900..acbb680 100644 --- a/Makefile +++ b/Makefile @@ -1,10 +1,10 @@ CHROMEDRIVER_VERSION=99.0.4844.17 -CHROMEDRIVER_DIR=${PWD}/geckodriver +CHROMEDRIVER_DIR=${PWD}/chromedriver -.PHONY: lint fmt build docs install test test_e2e gecko +.PHONY: lint fmt build docs install test test_e2e chromedriver build: - python setup.py sdist bdist_wheel + python -m build install: install_test install_docs install_pkg @@ -18,7 +18,7 @@ install_pkg: python -m pip install --upgrade pip wheel pip install . -gecko: +chromedriver: mkdir -p ${CHROMEDRIVER_DIR} wget -q -P ${CHROMEDRIVER_DIR} "http://chromedriver.storage.googleapis.com/${CHROMEDRIVER_VERSION}/chromedriver_linux64.zip" unzip ${CHROMEDRIVER_DIR}/chromedriver* -d ${CHROMEDRIVER_DIR} @@ -28,10 +28,10 @@ test: pytest test_e2e: - PATH=$$PWD/geckodriver:$$PATH pytest -m e2e --override-ini="addopts=" + PATH=$$PWD/chromedriver:$$PATH pytest -m e2e --override-ini="addopts=" clean: - rm -r build geckodriver + rm -r build chromedriver lint: docker run --rm -v /$$(pwd):/apps alpine/flake8 ./ diff --git a/README.md b/README.md index d664fb3..1fd8c66 100644 --- a/README.md +++ b/README.md @@ -3,9 +3,9 @@ [![Build Status](https://github.com/ad-m/python-anticaptcha/workflows/Python%20package/badge.svg)](https://github.com/ad-m/python-anticaptcha/actions?workflow=Python+package) [![PyPI](https://img.shields.io/pypi/v/python-anticaptcha.svg)](https://pypi.org/project/python-anticaptcha/) [![Chat](https://badges.gitter.im/python-anticaptcha/Lobby.svg)](https://gitter.im/python-anticaptcha/Lobby?utm_source=share-link&utm_medium=link&utm_campaign=share-link) -[![Python compatibility](https://img.shields.io/pypi/pyversions/python-anticaptcha.svg)](https://github.com/ad-m/python-anticaptcha/blob/master/setup.py) +[![Python compatibility](https://img.shields.io/pypi/pyversions/python-anticaptcha.svg)](https://github.com/ad-m/python-anticaptcha/blob/master/pyproject.toml) -Client library for solve captchas with [Anticaptcha.com support](http://getcaptchasolution.com/i1hvnzdymd). +Client library for solving captchas with [Anticaptcha.com support](http://getcaptchasolution.com/i1hvnzdymd). The library requires Python >= 3.9. The library is cyclically and automatically tested for proper operation. We are constantly making the best efforts for its effective operation. @@ -22,7 +22,7 @@ pip install python-anticaptcha ## Usage -To use this library do you need [Anticaptcha.com](http://getcaptchasolution.com/p9bwplkicx) API key. +To use this library you need [Anticaptcha.com](http://getcaptchasolution.com/p9bwplkicx) API key. You can pass the key explicitly or set the `ANTICAPTCHA_API_KEY` environment variable: @@ -52,12 +52,11 @@ job.join() print(job.get_solution_response()) ``` -The full integration example is available in file `examples/recaptcha.py`. +The full integration example is available in file `examples/recaptcha_request.py`. -If you only process few page many times to increase reliability, you can specify -whether the captcha is visible or not. This parameter is not required, as is the -system detects invisible sitekeys automatically, and needs several recursive -measures for automated training and analysis. For provide that pass +If you process the same page many times, to increase reliability you can specify +whether the captcha is visible or not. This parameter is not required, as the +system detects invisible sitekeys automatically. To provide that, pass `is_invisible` parameter to `NoCaptchaTaskProxylessTask` or `NoCaptchaTask` eg.: ```python @@ -138,7 +137,7 @@ pip install mitmproxy mitmweb -p 9190 -b 0.0.0.0 --ignore '.' --socks ``` -Next to in your application use something like: +Then in your application use something like: ```python proxy = Proxy.parse_url("socks5://123.123.123.123:9190") diff --git a/docs/conf.py b/docs/conf.py index aa39c12..dfe5b67 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -4,7 +4,7 @@ # # This file does only contain a selection of the most common options. For a # full list see the documentation: -# http://www.sphinx-doc.org/en/stable/config +# https://www.sphinx-doc.org/en/master/usage/configuration.html # -- Path setup -------------------------------------------------------------- @@ -21,13 +21,12 @@ # -- Project information ----------------------------------------------------- project = u"python-anticaptcha" -copyright = u"2018, Adam Dobrawy" +copyright = u"2018-2026, Adam Dobrawy" author = u"Adam Dobrawy" -# The short X.Y version +# Version is managed by setuptools-scm; leave empty for Sphinx version = u"" -# The full version, including alpha/beta/rc tags -release = u"0.2.0" +release = u"" # -- General configuration --------------------------------------------------- @@ -84,10 +83,9 @@ html_theme = "alabaster" try: - import sphinx_rtd_theme + import sphinx_rtd_theme # noqa: F401 html_theme = "sphinx_rtd_theme" - html_theme_path = [sphinx_rtd_theme.get_html_theme_path()] except ImportError: pass diff --git a/docs/development.rst b/docs/development.rst index ac3094c..fef5335 100644 --- a/docs/development.rst +++ b/docs/development.rst @@ -5,7 +5,7 @@ The project is open-source. Changes are managed through GitHub. Pull requests are particularly welcome. -All changes are automatically tested using TravisCI. +All changes are automatically tested using GitHub Actions. New release ----------- @@ -13,7 +13,7 @@ New release Follow these steps to publish the new release: * update changelog - use any text editor -* bump version - use ```bumpversion {major,minor,patch}``` -* build package - use ```python setup.py sdist bdist_wheel --universal``` -* upload release to PyPI - use ```twine upload dist/*``` -* push changes to GitHub - ```git push origin && git push --tags``` +* tag version - use ``git tag vX.Y.Z`` (versions are managed by ``setuptools-scm``) +* build package - use ``python -m build`` +* upload release to PyPI - use ``twine upload dist/*`` +* push changes to GitHub - ``git push origin && git push --tags`` diff --git a/docs/index.rst b/docs/index.rst index 422a2e1..81a0ced 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -6,7 +6,7 @@ Welcome to python-anticaptcha's documentation! ============================================== -Client library for solve captchas with `Anticaptcha.com support`_. +Client library for solving captchas with `Anticaptcha.com support`_. The library requires Python >= 3.9. The library is cyclically and automatically tested for proper operation. We are constantly making the best efforts for its effective operation. diff --git a/docs/usage.rst b/docs/usage.rst index 664ed88..96f224a 100644 --- a/docs/usage.rst +++ b/docs/usage.rst @@ -1,7 +1,7 @@ Usage ===== -To use this library do you need `Anticaptcha.com`_ API key. +To use this library you need `Anticaptcha.com`_ API key. You can pass the key explicitly or set the ``ANTICAPTCHA_API_KEY`` environment variable: @@ -32,12 +32,11 @@ Example snippet for Recaptcha: job.join() print(job.get_solution_response()) -The full integration example is available in file ``examples/recaptcha.py``. +The full integration example is available in file ``examples/recaptcha_request.py``. -If you only process few page many times to increase reliability, you can specify -whether the captcha is visible or not. This parameter is not required, as is the -system detects invisible sitekeys automatically, and needs several recursive -measures for automated training and analysis. For provide that pass +If you process the same page many times, to increase reliability you can specify +whether the captcha is visible or not. This parameter is not required, as the +system detects invisible sitekeys automatically. To provide that, pass ``is_invisible`` parameter to ``NoCaptchaTaskProxylessTask`` or ``NoCaptchaTask`` eg.: .. code:: python @@ -123,7 +122,7 @@ the possibility of simply launching such a server by: pip install mitmproxy mitmweb -p 9190 -b 0.0.0.0 --ignore '.' --socks -Next to in your application use something like: +Then in your application use something like: .. code:: python From 76d98bd366eed028ad6e1ab8091e95162aaedf44 Mon Sep 17 00:00:00 2001 From: Adam Dobrawy Date: Sat, 7 Mar 2026 14:53:14 +0100 Subject: [PATCH 2/3] Update release docs for trusted publishing via GitHub Actions Remove manual twine upload step from development docs and add trusted publishing changelog entry (PR #114). Co-Authored-By: Claude Opus 4.6 --- CHANGELOG.rst | 1 + docs/development.rst | 3 +-- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 08d913d..1d4365d 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -23,6 +23,7 @@ Changed - Migrate from ``setup.py`` / ``setup.cfg`` to ``pyproject.toml`` (PEP 621) (`#122 `_) - Switch README from RST to Markdown (`#126 `_) - Switch test runner from nose2 to pytest +- Switch PyPI publishing to trusted publishing via GitHub Actions (`#114 `_) - Fix ``RecaptchaV2EnterpriseTask`` missing proxyless base class inheritance - Fix ``ImageToTextTask.serialize()`` sending ``None`` values - Fix ``GeeTestTask`` incorrect inheritance diff --git a/docs/development.rst b/docs/development.rst index fef5335..e3a1680 100644 --- a/docs/development.rst +++ b/docs/development.rst @@ -14,6 +14,5 @@ Follow these steps to publish the new release: * update changelog - use any text editor * tag version - use ``git tag vX.Y.Z`` (versions are managed by ``setuptools-scm``) -* build package - use ``python -m build`` -* upload release to PyPI - use ``twine upload dist/*`` * push changes to GitHub - ``git push origin && git push --tags`` +* PyPI upload is handled automatically via GitHub Actions using `trusted publishing `_ From 26efc15509f9796f11a25515a250a9b777c1b6ef Mon Sep 17 00:00:00 2001 From: Adam Dobrawy Date: Sat, 7 Mar 2026 15:10:06 +0100 Subject: [PATCH 3/3] Add documentation for context manager, on_check callback, and ImageToTextTask inputs Document three recently added features that were missing usage examples: - Context manager support on AnticaptchaClient - on_check callback parameter on Job.join() - ImageToTextTask accepting file paths and raw bytes Co-Authored-By: Claude Opus 4.6 --- README.md | 32 ++++++++++++++++++++++++++++++-- docs/usage.rst | 33 +++++++++++++++++++++++++++++++-- 2 files changed, 61 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 1fd8c66..b91cb75 100644 --- a/README.md +++ b/README.md @@ -34,6 +34,14 @@ client = AnticaptchaClient("my-api-key") client = AnticaptchaClient() ``` +The client can be used as a context manager to ensure the underlying session is closed: + +```python +with AnticaptchaClient(api_key) as client: + job = client.create_task(task) + job.join() +``` + ### Solve recaptcha Example snippet for Recaptcha: @@ -81,9 +89,17 @@ Example snippet for text captcha: from python_anticaptcha import AnticaptchaClient, ImageToTextTask api_key = '174faff8fbc769e94a5862391ecfd010' -captcha_fp = open('examples/captcha_ms.jpeg', 'rb') client = AnticaptchaClient(api_key) -task = ImageToTextTask(captcha_fp) + +# From a file path: +task = ImageToTextTask('examples/captcha_ms.jpeg') + +# Or from raw bytes: +# task = ImageToTextTask(open('examples/captcha_ms.jpeg', 'rb').read()) + +# Or from a file object: +# task = ImageToTextTask(open('examples/captcha_ms.jpeg', 'rb')) + job = client.create_task(task) job.join() print(job.get_captcha_text()) @@ -110,6 +126,18 @@ job.join() print(job.get_token_response()) ``` +### Monitor solve progress + +You can pass an `on_check` callback to `job.join()` to monitor progress: + +```python +def progress(elapsed, status): + print(f"Elapsed: {elapsed}s, status: {status}") + +job = client.create_task(task) +job.join(on_check=progress) +``` + ### Report incorrect image Example snippet for reporting an incorrect image task: diff --git a/docs/usage.rst b/docs/usage.rst index 96f224a..633b1f1 100644 --- a/docs/usage.rst +++ b/docs/usage.rst @@ -13,6 +13,14 @@ You can pass the key explicitly or set the ``ANTICAPTCHA_API_KEY`` environment v # Or set ANTICAPTCHA_API_KEY environment variable client = AnticaptchaClient() +The client can be used as a context manager to ensure the underlying session is closed: + +.. code:: python + + with AnticaptchaClient(api_key) as client: + job = client.create_task(task) + job.join() + Solve recaptcha ############### @@ -64,9 +72,17 @@ Example snippet for text captcha: from python_anticaptcha import AnticaptchaClient, ImageToTextTask api_key = '174faff8fbc769e94a5862391ecfd010' - captcha_fp = open('examples/captcha_ms.jpeg', 'rb') client = AnticaptchaClient(api_key) - task = ImageToTextTask(captcha_fp) + + # From a file path: + task = ImageToTextTask('examples/captcha_ms.jpeg') + + # Or from raw bytes: + # task = ImageToTextTask(open('examples/captcha_ms.jpeg', 'rb').read()) + + # Or from a file object: + # task = ImageToTextTask(open('examples/captcha_ms.jpeg', 'rb')) + job = client.create_task(task) job.join() print(job.get_captcha_text()) @@ -93,6 +109,19 @@ Example snippet for funcaptcha: job.join() print(job.get_token_response()) +Monitor solve progress +###################### + +You can pass an ``on_check`` callback to ``job.join()`` to monitor progress: + +.. code:: python + + def progress(elapsed, status): + print(f"Elapsed: {elapsed}s, status: {status}") + + job = client.create_task(task) + job.join(on_check=progress) + Report incorrect image ######################