8000 Add Parameter `socket_options` to `HTTPXRequest` (#3935) · guillemap/python-telegram-bot@ea7e5a6 · GitHub
[go: up one dir, main page]

Skip to content

Commit ea7e5a6

Browse files
authored
Add Parameter socket_options to HTTPXRequest (python-telegram-bot#3935)
1 parent f67e8c0 commit ea7e5a6

File tree

4 files changed

+57
-19
lines changed

4 files changed

+57
-19
lines changed

.pre-commit-config.yaml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ repos:
2828
- --jobs=0
2929

3030
additional_dependencies:
31-
- httpx~=0.24.1
31+
- httpx~=0.25.0
3232
- tornado~=6.3.3
3333
- APScheduler~=3.10.4
3434
- cachetools~=5.3.1
@@ -44,7 +44,7 @@ repos:
4444
- types-pytz
4545
- types-cryptography
4646
- types-cachetools
47-
- httpx~=0.24.1
47+
- httpx~=0.25.0
4848
- tornado~=6.3.3
4949
- APScheduler~=3.10.4
5050
- cachetools~=5.3.1
@@ -83,7 +83,7 @@ repos:
8383
name: ruff
8484
files: ^(telegram|examples|tests)/.*\.py$
8585
additional_dependencies:
86-
- httpx~=0.24.1
86+
- httpx~=0.25.0
8787
- tornado~=6.3.3
8888
- APScheduler~=3.10.4
8989
- cachetools~=5.3.1

telegram/request/_httpxrequest.py

Lines changed: 32 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
# You should have received a copy of the GNU Lesser Public License
1818
# along with this program. If not, see [http://www.gnu.org/licenses/].
1919
"""This module contains methods to make POST and GET requests using the httpx library."""
20-
from typing import Optional, Tuple
20+
from typing import Collection, Optional, Tuple, Union
2121

2222
import httpx
2323

@@ -35,6 +35,12 @@
3535

3636
_LOGGER = get_logger(__name__, "HTTPXRequest")
3737

38+
_SocketOpt = Union[
39+
Tuple[int, int, int],
40+
Tuple[int, int, Union[bytes, bytearray]],
41+
Tuple[int, int, None, int],
42+
]
43+
3844

3945
class HTTPXRequest(BaseRequest):
4046
"""Implementation of :class:`~telegram.request.BaseRequest` using the library
@@ -91,6 +97,16 @@ class HTTPXRequest(BaseRequest):
9197
9298
.. versionchanged:: 20.5
9399
Accept ``"2"`` as a valid value.
100+
socket_options (Collection[:obj:`tuple`], optional): Socket options to be passed to the
101+
underlying `library \
102+
<https://www.encode.io/httpcore/async/#httpcore.AsyncConnectionPool.__init__>`_.
103+
104+
Note:
105+
The values accepted by this parameter depend on the operating system.
106+
This is a low-level parameter and should only be used if you are familiar with
107+
these concepts.
108+
109+
.. versionadded:: NEXT.VERSION
94110
95111
"""
96112

@@ -105,6 +121,7 @@ def __init__(
105121
connect_timeout: Optional[float] = 5.0,
106122
pool_timeout: Optional[float] = 1.0,
107123
http_version: HTTPVersion = "1.1",
124+
socket_options: Optional[Collection[_SocketOpt]] = None,
108125
):
109126
self._http_version = http_version
110127
timeout = httpx.Timeout(
@@ -122,16 +139,21 @@ def __init__(
122139
raise ValueError("`http_version` must be either '1.1', '2.0' or '2'.")
123140

124141
http1 = http_version == "1.1"
125-
126-
# See https://github.com/python-telegram-bot/python-telegram-bot/pull/3542
127-
# for why we need to use `dict()` here.
128-
self._client_kwargs = dict( # pylint: disable=use-dict-literal # noqa: C408
129-
timeout=timeout,
130-
proxies=proxy_url,
131-
limits=limits,
132-
http1=http1,
133-
http2=not http1,
142+
http_kwargs = {"http1": http1, "http2": not http1}
143+
transport = (
144+
httpx.AsyncHTTPTransport(
145+
socket_options=socket_options,
146+
)
147+
if socket_options
148+
else None
134149
)
150+
self._client_kwargs = {
151+
"timeout": timeout,
152+
"proxies": proxy_url,
153+
"limits": limits,
154+
"transport": transport,
155+
**http_kwargs,
156+
}
135157

136158
try:
137159
self._client = self._build_client()
@@ -206,12 +228,6 @@ async def do_request(
206228
pool=pool_timeout,
207229
)
208230

209-
# TODO p0: On Linux, use setsockopt to properly set socket level keepalive.
210-
# (socket.IPPROTO_TCP, socket.TCP_KEEPIDLE, 120)
211-
# (socket.IPPROTO_TCP, socket.TCP_KEEPINTVL, 30)
212-
# (socket.IPPROTO_TCP, socket.TCP_KEEPCNT, 8)
213-
# TODO p4: Support setsockopt on lesser platforms than Linux.
214-
215231
files = request_data.multipart_data if request_data else None
216232
data = request_data.json_parameters if request_data else None
217233

tests/ext/test_applicationbuilder.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,7 @@ class Client:
9191
limits: object
9292
http1: object
9393
http2: object
94+
transport: object = None
9495

9596
monkeypatch.setattr(httpx, "AsyncClient", Client)
9697

@@ -322,6 +323,7 @@ class Client:
322323
limits: object
323324
http1: object
324325
http2: object
326+
transport: object = None
325327

326328
monkeypatch.setattr(httpx, "AsyncClient", Client)
327329

tests/request/test_request.py

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828

2929
import httpx
3030
import pytest
31+
from httpx import AsyncHTTPTransport
3132

3233
from telegram._utils.defaultvalue import DEFAULT_NONE
3334
from telegram.error import (
@@ -366,6 +367,7 @@ class Client:
366367
limits: object
367368
http1: object
368369
http2: object
370+
transport: object = None
369371

370372
monkeypatch.setattr(httpx, "AsyncClient", Client)
371373

@@ -618,6 +620,24 @@ async def request(_, **kwargs):
618620

619621
assert exc_info.value.__cause__ is pool_timeout
620622

623+
async def test_socket_opts(self, monkeypatch):
624+
transport_kwargs = {}
625+
transport_init = AsyncHTTPTransport.__init__
626+
627+
def init_transport(*args, **kwargs):
628+
nonlocal transport_kwargs
629+
transport_kwargs = kwargs.copy()
630+
transport_init(*args, **kwargs)
631+
632+
monkeypatch.setattr(AsyncHTTPTransport, "__init__", init_transport)
633+
634+
HTTPXRequest()
635+
assert "socket_options" not in transport_kwargs
636+
637+
transport_kwargs = {}
638+
HTTPXRequest(socket_options=((1, 2, 3),))
639+
assert transport_kwargs["socket_options"] == ((1, 2, 3),)
640+
621641

622642
@pytest.mark.skipif(not TEST_WITH_OPT_DEPS, reason="No need to run this twice")
623643
class TestHTTPXRequestWithRequest:

0 commit comments

Comments
 (0)
0