Skip to content

Commit 5ae33a0

Browse files
vdusekclaude
andauthored
feat!: Make HTTP client pluggable with abstract base classes (#641)
## Summary - Introduce `HttpClient` and `HttpClientAsync` ABCs that users can extend to provide custom HTTP client implementations via `ApifyClient(http_client=...)` and `ApifyClientAsync(http_client=...)` - Factor impit-specific logic into `ImpitHttpClient`/`ImpitHttpClientAsync`, keeping `_base.py` free of any `impit` dependency - Add `HttpResponse` protocol with full streaming support (`iter_bytes`, `aiter_bytes`, `read`, `aread`, `close`, `aclose`) - Export all public types (`HttpClient`, `HttpClientAsync`, `HttpResponse`, `ImpitHttpClient`, `ImpitHttpClientAsync`) from `apify_client` ## Issue - Closes: #416 Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 3aab481 commit 5ae33a0

19 files changed

+931
-233
lines changed

scripts/check_async_docstrings.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,12 @@
1111

1212
found_issues = False
1313

14+
# Methods where the async docstring is intentionally different from the sync one
15+
# (e.g. because they accept different parameter types).
16+
SKIPPED_METHODS = {
17+
'with_custom_http_client',
18+
}
19+
1420
# Get the directory of the source files
1521
clients_path = Path(__file__).parent.resolve() / '../src/apify_client'
1622

@@ -37,6 +43,10 @@
3743
if len(async_method.decorators) and str(async_method.decorators[0].value) == 'ignore_docs':
3844
continue
3945

46+
# Skip methods whose docstrings are intentionally different
47+
if async_method.name in SKIPPED_METHODS:
48+
continue
49+
4050
# If the sync method has a docstring, check if it matches the async dostring
4151
if sync_method and isinstance(sync_method.value[0].value, str):
4252
sync_docstring = sync_method.value[0].value

scripts/fix_async_docstrings.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,12 @@
66
from redbaron import RedBaron
77
from utils import sync_to_async_docstring
88

9+
# Methods where the async docstring is intentionally different from the sync one
10+
# (e.g. because they accept different parameter types).
11+
SKIPPED_METHODS = {
12+
'with_custom_http_client',
13+
}
14+
915
# Get the directory of the source files
1016
clients_path = Path(__file__).parent.resolve() / '../src/apify_client'
1117

@@ -34,6 +40,10 @@
3440
if len(async_method.decorators) and str(async_method.decorators[0].value) == 'ignore_docs':
3541
continue
3642

43+
# Skip methods whose docstrings are intentionally different
44+
if async_method.name in SKIPPED_METHODS:
45+
continue
46+
3747
# Skip methods that don't exist in the sync class
3848
if sync_method is None:
3949
continue

src/apify_client/__init__.py

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,23 @@
11
from importlib import metadata
22

33
from ._apify_client import ApifyClient, ApifyClientAsync
4+
from ._http_clients import (
5+
HttpClient,
6+
HttpClientAsync,
7+
HttpResponse,
8+
ImpitHttpClient,
9+
ImpitHttpClientAsync,
10+
)
411

512
__version__ = metadata.version('apify-client')
613

7-
__all__ = ['ApifyClient', 'ApifyClientAsync', '__version__']
14+
__all__ = [
15+
'ApifyClient',
16+
'ApifyClientAsync',
17+
'HttpClient',
18+
'HttpClientAsync',
19+
'HttpResponse',
20+
'ImpitHttpClient',
21+
'ImpitHttpClientAsync',
22+
'__version__',
23+
]

0 commit comments

Comments
 (0)