Skip to content

Commit ab25d07

Browse files
authored
refactor: Rename the HTTPX extra and clients to httpx2 (#1048)
Renames the optional extra `httpx` to `httpx2`, and `HttpxHttpClient` / `HttpxHttpClientAsync` to `Httpx2HttpClient` / `Httpx2HttpClientAsync`, along with the private module, the docs examples, and the test ids. Once httpx releases 1.0 with a new API, an extra named `httpx` that installs `httpx2` would confuse users (see #1046 (comment)). Neither name has shipped in a stable release, so nothing is breaking. Kept as is: the `import httpx2 as httpx` alias inside the module, "HTTPX" as the library name in prose, and the historical v2 upgrade note. Follows up on #1046. *✍️ Drafted by Claude Code*
1 parent 2731e14 commit ab25d07

16 files changed

Lines changed: 81 additions & 82 deletions

.rules.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ Docstrings are written on sync clients and **automatically copied** to async cli
6363
- `HttpClient`/`HttpClientAsync` — base classes in `http_clients/_base.py` holding the shared request pipeline (retries,
6464
timeouts, API errors); transports implement the `send_request`, error-classification, and lifecycle hooks
6565
- `ImpitHttpClient`/`ImpitHttpClientAsync` — default implementation (Rust-based Impit)
66-
- `HttpxHttpClient`/`HttpxHttpClientAsync` — built-in alternative behind the `httpx` optional extra
66+
- `Httpx2HttpClient`/`Httpx2HttpClientAsync` — built-in alternative behind the `httpx2` optional extra
6767
- `HttpResponse` — Protocol (not a concrete class) for response objects
6868
- Users can plug in custom HTTP clients via `ApifyClient.with_custom_http_client()`
6969

README.md

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -58,14 +58,14 @@
5858
```
5959

6060
[Impit](https://github.com/apify/impit) is the default HTTP client and is installed automatically. To use the
61-
built-in [HTTPX](https://github.com/pydantic/httpx2) client instead, install its optional extra and pass
62-
`http_client=HttpxHttpClient()` to `ApifyClient.with_custom_http_client()`. The extra installs `httpx2`,
63-
Pydantic's maintained continuation of HTTPX:
61+
built-in [HTTPX](https://github.com/pydantic/httpx2) client instead, install the optional `httpx2` extra, which
62+
provides Pydantic's maintained continuation of HTTPX, and pass `http_client=Httpx2HttpClient()` to
63+
`ApifyClient.with_custom_http_client()`:
6464
6565
```bash
66-
pip install "apify-client[httpx]"
66+
pip install "apify-client[httpx2]"
6767
# or
68-
uv add "apify-client[httpx]"
68+
uv add "apify-client[httpx2]"
6969
```
7070
7171
- From [conda-forge](https://anaconda.org/conda-forge/apify-client), it can be installed with [conda](https://docs.conda.io/en/latest/):

docs/01_introduction/index.mdx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -63,12 +63,12 @@ For better request-body compression, opt in to `brotli`, which compresses better
6363

6464
For details, see [HTTP compression](../02_concepts/13_http_compression.mdx).
6565

66-
The client uses [Impit](https://github.com/apify/impit) as its default HTTP transport. To use the built-in [HTTPX](https://github.com/pydantic/httpx2) transport, install the optional `httpx` extra. The extra installs `httpx2`, Pydantic's maintained continuation of HTTPX:
66+
The client uses [Impit](https://github.com/apify/impit) as its default HTTP transport. To use the built-in [HTTPX](https://github.com/pydantic/httpx2) transport, install the optional `httpx2` extra, which provides Pydantic's maintained continuation of HTTPX:
6767

6868
<Tabs>
6969
<TabItem value="PyPI" label="PyPI" default>
7070
```bash
71-
pip install "apify-client[httpx]"
71+
pip install "apify-client[httpx2]"
7272
```
7373
</TabItem>
7474
<TabItem value="conda-forge" label="conda-forge">

docs/02_concepts/10_custom_http_clients.mdx

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,8 @@ import ApiLink from '@theme/ApiLink';
1111

1212
import DefaultHttpClientAsyncExample from '!!raw-loader!./code/10_default_http_client_async.py';
1313
import DefaultHttpClientSyncExample from '!!raw-loader!./code/10_default_http_client_sync.py';
14-
import HttpxHttpClientAsyncExample from '!!raw-loader!./code/10_httpx_client_async.py';
15-
import HttpxHttpClientSyncExample from '!!raw-loader!./code/10_httpx_client_sync.py';
14+
import Httpx2HttpClientAsyncExample from '!!raw-loader!./code/10_httpx2_client_async.py';
15+
import Httpx2HttpClientSyncExample from '!!raw-loader!./code/10_httpx2_client_sync.py';
1616

1717
import ArchitectureImportsExample from '!!raw-loader!./code/10_architecture_imports.py';
1818

@@ -47,30 +47,30 @@ You can configure the default client through the <ApiLink to="class/ApifyClient"
4747

4848
## Built-in HTTPX client
4949

50-
The package also provides <ApiLink to="class/HttpxHttpClient">`HttpxHttpClient`</ApiLink> and <ApiLink to="class/HttpxHttpClientAsync">`HttpxHttpClientAsync`</ApiLink>. They use the same request preparation, compression, retry policy, timeout tiers and growth, error handling, logging, and statistics as the default Impit clients, with [HTTPX](https://github.com/pydantic/httpx2) as the transport.
50+
The package also provides <ApiLink to="class/Httpx2HttpClient">`Httpx2HttpClient`</ApiLink> and <ApiLink to="class/Httpx2HttpClientAsync">`Httpx2HttpClientAsync`</ApiLink>. They use the same request preparation, compression, retry policy, timeout tiers and growth, error handling, logging, and statistics as the default Impit clients, with [HTTPX](https://github.com/pydantic/httpx2) as the transport.
5151

52-
HTTPX is an optional dependency. Install `apify-client[httpx]`, then pass the appropriate client to <ApiLink to="class/ApifyClient#with_custom_http_client">`ApifyClient.with_custom_http_client`</ApiLink>. The extra installs `httpx2`, Pydantic's maintained continuation of HTTPX. Impit remains the default even when the HTTPX extra is installed.
52+
HTTPX is an optional dependency provided by the `httpx2` package, Pydantic's maintained continuation of HTTPX. Install `apify-client[httpx2]`, then pass the appropriate client to <ApiLink to="class/ApifyClient#with_custom_http_client">`ApifyClient.with_custom_http_client`</ApiLink>. Impit remains the default even when the extra is installed.
5353

5454
```bash
55-
pip install "apify-client[httpx]"
55+
pip install "apify-client[httpx2]"
5656
# or
57-
uv add "apify-client[httpx]"
57+
uv add "apify-client[httpx2]"
5858
```
5959

6060
<Tabs>
61-
<TabItem value="HttpxAsyncExample" label="Async client" default>
61+
<TabItem value="Httpx2AsyncExample" label="Async client" default>
6262
<CodeBlock className="language-python">
63-
{HttpxHttpClientAsyncExample}
63+
{Httpx2HttpClientAsyncExample}
6464
</CodeBlock>
6565
</TabItem>
66-
<TabItem value="HttpxSyncExample" label="Sync client">
66+
<TabItem value="Httpx2SyncExample" label="Sync client">
6767
<CodeBlock className="language-python">
68-
{HttpxHttpClientSyncExample}
68+
{Httpx2HttpClientSyncExample}
6969
</CodeBlock>
7070
</TabItem>
7171
</Tabs>
7272

73-
Configure retries, timeout tiers, default headers, and compression on the HTTPX client instance. The token passed to `with_custom_http_client` is applied automatically unless the HTTP client already has an `Authorization` header. The examples use the clients as context managers so their connection pools are closed deterministically. If a context manager doesn't fit your application's lifecycle, call `close()` on `HttpxHttpClient` or `await aclose()` on `HttpxHttpClientAsync` during shutdown.
73+
Configure retries, timeout tiers, default headers, and compression on the HTTPX client instance. The token passed to `with_custom_http_client` is applied automatically unless the HTTP client already has an `Authorization` header. The examples use the clients as context managers so their connection pools are closed deterministically. If a context manager doesn't fit your application's lifecycle, call `close()` on `Httpx2HttpClient` or `await aclose()` on `Httpx2HttpClientAsync` during shutdown.
7474

7575
Timeout values are passed to the selected transport. Impit enforces them as a deadline for the whole request, body included. HTTPX applies them to each socket operation instead, so a response whose body arrives slowly keeps resetting the timeout and can outlast both the requested timeout and `timeout_max`. The `no_timeout` option disables HTTPX's timeouts.
7676

docs/02_concepts/code/10_httpx_client_async.py renamed to docs/02_concepts/code/10_httpx2_client_async.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
import asyncio
22

33
from apify_client import ApifyClientAsync
4-
from apify_client.http_clients import HttpxHttpClientAsync
4+
from apify_client.http_clients import Httpx2HttpClientAsync
55

66
TOKEN = 'MY-APIFY-TOKEN'
77

88

99
async def main() -> None:
10-
async with HttpxHttpClientAsync() as http_client:
10+
async with Httpx2HttpClientAsync() as http_client:
1111
client = ApifyClientAsync.with_custom_http_client(
1212
token=TOKEN,
1313
http_client=http_client,

docs/02_concepts/code/10_httpx_client_sync.py renamed to docs/02_concepts/code/10_httpx2_client_sync.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
from apify_client import ApifyClient
2-
from apify_client.http_clients import HttpxHttpClient
2+
from apify_client.http_clients import Httpx2HttpClient
33

44
TOKEN = 'MY-APIFY-TOKEN'
55

66

77
def main() -> None:
8-
with HttpxHttpClient() as http_client:
8+
with Httpx2HttpClient() as http_client:
99
client = ApifyClient.with_custom_http_client(
1010
token=TOKEN,
1111
http_client=http_client,

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ dependencies = [
3434

3535
[project.optional-dependencies]
3636
brotli = ["brotli>=1.0.9"]
37-
httpx = ["httpx2>=2.0.0"]
37+
httpx2 = ["httpx2>=2.0.0"]
3838

3939
[project.urls]
4040
"Apify Homepage" = "https://apify.com"

src/apify_client/http_clients/__init__.py

Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -5,17 +5,16 @@
55

66
_install_import_hook(__name__)
77

8-
# The HTTPX clients depend on `httpx2`, installed by the optional `httpx` extra, so the import is wrapped in
9-
# try_import. Accessing them without the extra installed raises a clear ImportError instead of failing at package
10-
# import time.
8+
# `httpx2` is an optional extra, so the import is wrapped in try_import. Accessing the HTTPX clients without the
9+
# extra installed raises a clear ImportError instead of failing at package import time.
1110
with _try_import(
1211
__name__,
13-
'HttpxHttpClient',
14-
'HttpxHttpClientAsync',
12+
'Httpx2HttpClient',
13+
'Httpx2HttpClientAsync',
1514
dependency_name='httpx2',
16-
extra_name='httpx',
17-
) as _httpx_import:
18-
from apify_client.http_clients._httpx import HttpxHttpClient, HttpxHttpClientAsync
15+
extra_name='httpx2',
16+
) as _httpx2_import:
17+
from apify_client.http_clients._httpx2 import Httpx2HttpClient, Httpx2HttpClientAsync
1918

2019
__all__ = [
2120
'HttpClient',
@@ -25,8 +24,8 @@
2524
'ImpitHttpClientAsync',
2625
]
2726

28-
if _httpx_import.available:
27+
if _httpx2_import.available:
2928
__all__ += [
30-
'HttpxHttpClient',
31-
'HttpxHttpClientAsync',
29+
'Httpx2HttpClient',
30+
'Httpx2HttpClientAsync',
3231
]
Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@
3838

3939

4040
@docs_group('HTTP clients')
41-
class HttpxHttpClient(HttpClient):
41+
class Httpx2HttpClient(HttpClient):
4242
"""Synchronous HTTP client for the Apify API built on top of [HTTPX](https://github.com/pydantic/httpx2).
4343
4444
This client wraps `httpx.Client` and adds automatic retries with exponential backoff for rate-limited
@@ -48,8 +48,8 @@ class HttpxHttpClient(HttpClient):
4848
whose body arrives slowly keeps resetting it and can outlast both the requested timeout and `timeout_max`. The
4949
default Impit client enforces the same value as a deadline for the whole request, body included.
5050
51-
Requires the `httpx` extra: `pip install "apify-client[httpx]"`. That extra installs `httpx2`, Pydantic's
52-
maintained continuation of HTTPX, which this module imports under the `httpx` name.
51+
Requires the `httpx2` extra: `pip install "apify-client[httpx2]"`. The `httpx2` package is Pydantic's maintained
52+
continuation of HTTPX, which this module imports under the `httpx` name.
5353
"""
5454

5555
def __init__(
@@ -142,7 +142,7 @@ def _clear_response_cookies(self, _response: httpx.Response) -> None:
142142

143143

144144
@docs_group('HTTP clients')
145-
class HttpxHttpClientAsync(HttpClientAsync):
145+
class Httpx2HttpClientAsync(HttpClientAsync):
146146
"""Asynchronous HTTP client for the Apify API built on top of [HTTPX](https://github.com/pydantic/httpx2).
147147
148148
This client wraps `httpx.AsyncClient` and adds automatic retries with exponential backoff for rate-limited
@@ -152,8 +152,8 @@ class HttpxHttpClientAsync(HttpClientAsync):
152152
whose body arrives slowly keeps resetting it and can outlast both the requested timeout and `timeout_max`. The
153153
default Impit client enforces the same value as a deadline for the whole request, body included.
154154
155-
Requires the `httpx` extra: `pip install "apify-client[httpx]"`. That extra installs `httpx2`, Pydantic's
156-
maintained continuation of HTTPX, which this module imports under the `httpx` name.
155+
Requires the `httpx2` extra: `pip install "apify-client[httpx2]"`. The `httpx2` package is Pydantic's maintained
156+
continuation of HTTPX, which this module imports under the `httpx` name.
157157
"""
158158

159159
def __init__(

tests/integration/conftest.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,8 @@
1919
from apify_client._consts import DEFAULT_API_URL
2020
from apify_client._utils.crypto import create_hmac_signature, create_storage_content_signature
2121
from apify_client.http_clients import (
22-
HttpxHttpClient,
23-
HttpxHttpClientAsync,
22+
Httpx2HttpClient,
23+
Httpx2HttpClientAsync,
2424
ImpitHttpClient,
2525
ImpitHttpClientAsync,
2626
)
@@ -109,7 +109,7 @@ def test_kvs_of_another_user(api_token_2: str) -> Generator[KvsFixture]:
109109
@pytest.fixture(
110110
params=[
111111
pytest.param(HttpClientClasses(sync=ImpitHttpClient, async_=ImpitHttpClientAsync), id='impit'),
112-
pytest.param(HttpClientClasses(sync=HttpxHttpClient, async_=HttpxHttpClientAsync), id='httpx'),
112+
pytest.param(HttpClientClasses(sync=Httpx2HttpClient, async_=Httpx2HttpClientAsync), id='httpx2'),
113113
]
114114
)
115115
def http_client_classes(request: pytest.FixtureRequest) -> HttpClientClasses:

0 commit comments

Comments
 (0)