Skip to content

Commit 0a79cf6

Browse files
ad-mAdam Dobrawyclaude
authored
Accept file paths, bytes, and file objects in ImageToTextTask (#119)
ImageToTextTask now accepts three input types instead of only file objects: file path (str/Path), raw bytes, or file-like object (existing behavior). The image is base64-encoded eagerly in __init__ instead of lazily in serialize(). Co-authored-by: Adam Dobrawy <naczelnik@jawne.info.pl> Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 1365e65 commit 0a79cf6

2 files changed

Lines changed: 35 additions & 10 deletions

File tree

python_anticaptcha/tasks.py

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
from __future__ import annotations
22

33
import base64
4-
from typing import Any, BinaryIO
4+
from pathlib import Path
5+
from typing import Any, BinaryIO, Union
56

67

78
class BaseTask:
@@ -139,7 +140,7 @@ class FunCaptchaTask(ProxyMixin, UserAgentMixin, CookieMixin, FunCaptchaProxyles
139140

140141
class ImageToTextTask(BaseTask):
141142
type = "ImageToTextTask"
142-
fp = None
143+
_body = None
143144
phrase = None
144145
case = None
145146
numeric = None
@@ -151,7 +152,7 @@ class ImageToTextTask(BaseTask):
151152

152153
def __init__(
153154
self,
154-
fp: BinaryIO,
155+
image: Union[str, Path, bytes, BinaryIO],
155156
phrase: bool | None = None,
156157
case: bool | None = None,
157158
numeric: int | None = None,
@@ -163,7 +164,13 @@ def __init__(
163164
*args: Any,
164165
**kwargs: Any,
165166
) -> None:
166-
self.fp = fp
167+
if isinstance(image, (str, Path)):
168+
with open(image, "rb") as f:
169+
self._body = base64.b64encode(f.read()).decode("utf-8")
170+
elif isinstance(image, bytes):
171+
self._body = base64.b64encode(image).decode("utf-8")
172+
else:
173+
self._body = base64.b64encode(image.read()).decode("utf-8")
167174
self.phrase = phrase
168175
self.case = case
169176
self.numeric = numeric
@@ -176,7 +183,7 @@ def __init__(
176183

177184
def serialize(self, **result: Any) -> dict[str, Any]:
178185
data = super().serialize(**result)
179-
data["body"] = base64.b64encode(self.fp.read()).decode("utf-8")
186+
data["body"] = self._body
180187
if self.phrase is not None:
181188
data["phrase"] = self.phrase
182189
if self.case is not None:

tests/test_tasks.py

Lines changed: 23 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -138,22 +138,40 @@ def test_type(self):
138138
class TestImageToTextTask:
139139
def test_serialize_base64(self):
140140
fp = io.BytesIO(b"fake image data")
141-
task = ImageToTextTask(fp=fp)
141+
task = ImageToTextTask(fp)
142142
data = task.serialize()
143143
assert data["type"] == "ImageToTextTask"
144144
assert data["body"] == "ZmFrZSBpbWFnZSBkYXRh"
145145

146+
def test_from_bytes(self):
147+
task = ImageToTextTask(b"fake image data")
148+
data = task.serialize()
149+
assert data["type"] == "ImageToTextTask"
150+
assert data["body"] == "ZmFrZSBpbWFnZSBkYXRh"
151+
152+
def test_from_file_path(self, tmp_path):
153+
img = tmp_path / "captcha.jpeg"
154+
img.write_bytes(b"fake image data")
155+
task = ImageToTextTask(str(img))
156+
data = task.serialize()
157+
assert data["body"] == "ZmFrZSBpbWFnZSBkYXRh"
158+
159+
def test_from_pathlib_path(self, tmp_path):
160+
img = tmp_path / "captcha.jpeg"
161+
img.write_bytes(b"fake image data")
162+
task = ImageToTextTask(img)
163+
data = task.serialize()
164+
assert data["body"] == "ZmFrZSBpbWFnZSBkYXRh"
165+
146166
def test_optional_fields_omitted(self):
147-
fp = io.BytesIO(b"data")
148-
task = ImageToTextTask(fp=fp)
167+
task = ImageToTextTask(b"data")
149168
data = task.serialize()
150169
for key in ["phrase", "case", "numeric", "math", "minLength", "maxLength", "comment", "websiteUrl"]:
151170
assert key not in data
152171

153172
def test_optional_fields_included(self):
154-
fp = io.BytesIO(b"data")
155173
task = ImageToTextTask(
156-
fp=fp, phrase=True, case=True, numeric=1,
174+
b"data", phrase=True, case=True, numeric=1,
157175
math=False, min_length=3, max_length=10,
158176
comment="solve this", website_url="https://example.com",
159177
)

0 commit comments

Comments
 (0)