mirror of
https://github.com/python-telegram-bot/python-telegram-bot.git
synced 2025-01-03 09:49:21 +01:00
Revert to HTTP/1.1 as Default and make HTTP/2 an Optional Dependency (#3576)
Co-authored-by: Bibo-Joshi <22366557+Bibo-Joshi@users.noreply.github.com> Co-authored-by: Harshil <37377066+harshil21@users.noreply.github.com>
This commit is contained in:
parent
ec20f27a82
commit
800598ced4
11 changed files with 164 additions and 41 deletions
3
.github/workflows/test.yml
vendored
3
.github/workflows/test.yml
vendored
|
@ -50,7 +50,8 @@ jobs:
|
||||||
# - without ratelimiter
|
# - without ratelimiter
|
||||||
# - without webhooks
|
# - without webhooks
|
||||||
# - without arbitrary callback data
|
# - without arbitrary callback data
|
||||||
# - without socks suppport
|
# - without socks support
|
||||||
|
# - without http2 support
|
||||||
TO_TEST="test_no_passport.py or test_datetime.py or test_defaults.py or test_jobqueue.py or test_applicationbuilder.py or test_ratelimiter.py or test_updater.py or test_callbackdatacache.py or test_request.py"
|
TO_TEST="test_no_passport.py or test_datetime.py or test_defaults.py or test_jobqueue.py or test_applicationbuilder.py or test_ratelimiter.py or test_updater.py or test_callbackdatacache.py or test_request.py"
|
||||||
pytest -v --cov -k "${TO_TEST}"
|
pytest -v --cov -k "${TO_TEST}"
|
||||||
status=$?
|
status=$?
|
||||||
|
|
|
@ -135,9 +135,8 @@ As these features are *optional*, the corresponding 3rd party dependencies are n
|
||||||
Instead, they are listed as optional dependencies.
|
Instead, they are listed as optional dependencies.
|
||||||
This allows to avoid unnecessary dependency conflicts for users who don't need the optional features.
|
This allows to avoid unnecessary dependency conflicts for users who don't need the optional features.
|
||||||
|
|
||||||
The only required dependency is `httpx[http2] ~= 0.23.3 <https://www.python-httpx.org>`_ for
|
The only required dependency is `httpx ~= 0.23.3 <https://www.python-httpx.org>`_ for
|
||||||
``telegram.request.HTTPXRequest``, the default networking backend. By default, HTTP/2 is used, as it
|
``telegram.request.HTTPXRequest``, the default networking backend.
|
||||||
provides greater performance and stability, specially for concurrent requests.
|
|
||||||
|
|
||||||
``python-telegram-bot`` is most useful when used along with additional libraries.
|
``python-telegram-bot`` is most useful when used along with additional libraries.
|
||||||
To minimize dependency conflicts, we try to be liberal in terms of version requirements on the (optional) dependencies.
|
To minimize dependency conflicts, we try to be liberal in terms of version requirements on the (optional) dependencies.
|
||||||
|
@ -151,6 +150,7 @@ PTB can be installed with optional dependencies:
|
||||||
|
|
||||||
* ``pip install python-telegram-bot[passport]`` installs the `cryptography>=39.0.1 <https://cryptography.io/en/stable>`_ library. Use this, if you want to use Telegram Passport related functionality.
|
* ``pip install python-telegram-bot[passport]`` installs the `cryptography>=39.0.1 <https://cryptography.io/en/stable>`_ library. Use this, if you want to use Telegram Passport related functionality.
|
||||||
* ``pip install python-telegram-bot[socks]`` installs `httpx[socks] <https://www.python-httpx.org/#dependencies>`_. Use this, if you want to work behind a Socks5 server.
|
* ``pip install python-telegram-bot[socks]`` installs `httpx[socks] <https://www.python-httpx.org/#dependencies>`_. Use this, if you want to work behind a Socks5 server.
|
||||||
|
* ``pip install python-telegram-bot[http2]`` installs `httpx[http2] <https://www.python-httpx.org/#dependencies>`_. Use this, if you want to use HTTP/2.
|
||||||
* ``pip install python-telegram-bot[rate-limiter]`` installs `aiolimiter~=1.0.0 <https://aiolimiter.readthedocs.io/en/stable/>`_. Use this, if you want to use ``telegram.ext.AIORateLimiter``.
|
* ``pip install python-telegram-bot[rate-limiter]`` installs `aiolimiter~=1.0.0 <https://aiolimiter.readthedocs.io/en/stable/>`_. Use this, if you want to use ``telegram.ext.AIORateLimiter``.
|
||||||
* ``pip install python-telegram-bot[webhooks]`` installs the `tornado~=6.2 <https://www.tornadoweb.org/en/stable/>`_ library. Use this, if you want to use ``telegram.ext.Updater.start_webhook``/``telegram.ext.Application.run_webhook``.
|
* ``pip install python-telegram-bot[webhooks]`` installs the `tornado~=6.2 <https://www.tornadoweb.org/en/stable/>`_ library. Use this, if you want to use ``telegram.ext.Updater.start_webhook``/``telegram.ext.Application.run_webhook``.
|
||||||
* ``pip install python-telegram-bot[callback-data]`` installs the `cachetools~=5.3.0 <https://cachetools.readthedocs.io/en/latest/>`_ library. Use this, if you want to use `arbitrary callback_data <https://github.com/python-telegram-bot/python-telegram-bot/wiki/Arbitrary-callback_data>`_.
|
* ``pip install python-telegram-bot[callback-data]`` installs the `cachetools~=5.3.0 <https://cachetools.readthedocs.io/en/latest/>`_ library. Use this, if you want to use `arbitrary callback_data <https://github.com/python-telegram-bot/python-telegram-bot/wiki/Arbitrary-callback_data>`_.
|
||||||
|
|
|
@ -136,9 +136,8 @@ As these features are *optional*, the corresponding 3rd party dependencies are n
|
||||||
Instead, they are listed as optional dependencies.
|
Instead, they are listed as optional dependencies.
|
||||||
This allows to avoid unnecessary dependency conflicts for users who don't need the optional features.
|
This allows to avoid unnecessary dependency conflicts for users who don't need the optional features.
|
||||||
|
|
||||||
The only required dependency is `httpx[http2] ~= 0.23.3 <https://www.python-httpx.org>`_ for
|
The only required dependency is `httpx ~= 0.23.3 <https://www.python-httpx.org>`_ for
|
||||||
``telegram.request.HTTPXRequest``, the default networking backend. By default, HTTP/2 is used, as
|
``telegram.request.HTTPXRequest``, the default networking backend.
|
||||||
it provides greater performance and stability, specially for concurrent requests.
|
|
||||||
|
|
||||||
``python-telegram-bot`` is most useful when used along with additional libraries.
|
``python-telegram-bot`` is most useful when used along with additional libraries.
|
||||||
To minimize dependency conflicts, we try to be liberal in terms of version requirements on the (optional) dependencies.
|
To minimize dependency conflicts, we try to be liberal in terms of version requirements on the (optional) dependencies.
|
||||||
|
@ -152,6 +151,7 @@ PTB can be installed with optional dependencies:
|
||||||
|
|
||||||
* ``pip install python-telegram-bot-raw[passport]`` installs the `cryptography>=39.0.1 <https://cryptography.io/en/stable>`_ library. Use this, if you want to use Telegram Passport related functionality.
|
* ``pip install python-telegram-bot-raw[passport]`` installs the `cryptography>=39.0.1 <https://cryptography.io/en/stable>`_ library. Use this, if you want to use Telegram Passport related functionality.
|
||||||
* ``pip install python-telegram-bot-raw[socks]`` installs `httpx[socks] <https://www.python-httpx.org/#dependencies>`_. Use this, if you want to work behind a Socks5 server.
|
* ``pip install python-telegram-bot-raw[socks]`` installs `httpx[socks] <https://www.python-httpx.org/#dependencies>`_. Use this, if you want to work behind a Socks5 server.
|
||||||
|
* ``pip install python-telegram-bot[http2]`` installs `httpx[http2] <https://www.python-httpx.org/#dependencies>`_. Use this, if you want to use HTTP/2.
|
||||||
|
|
||||||
To install multiple optional dependencies, separate them by commas, e.g. ``pip install python-telegram-bot-raw[passport,socks]``.
|
To install multiple optional dependencies, separate them by commas, e.g. ``pip install python-telegram-bot-raw[passport,socks]``.
|
||||||
|
|
||||||
|
|
|
@ -11,6 +11,7 @@
|
||||||
# versions and only increase the lower bound if necessary
|
# versions and only increase the lower bound if necessary
|
||||||
|
|
||||||
httpx[socks] # socks
|
httpx[socks] # socks
|
||||||
|
httpx[http2] # http2
|
||||||
cryptography!=3.4,!=3.4.1,!=3.4.2,!=3.4.3,>=39.0.1 # passport
|
cryptography!=3.4,!=3.4.1,!=3.4.2,!=3.4.3,>=39.0.1 # passport
|
||||||
aiolimiter~=1.0.0 # rate-limiter!ext
|
aiolimiter~=1.0.0 # rate-limiter!ext
|
||||||
|
|
||||||
|
|
|
@ -6,5 +6,4 @@
|
||||||
# versions and only increase the lower bound if necessary
|
# versions and only increase the lower bound if necessary
|
||||||
|
|
||||||
# httpx has no stable release yet, so let's be cautious for now
|
# httpx has no stable release yet, so let's be cautious for now
|
||||||
# HTTP/2 is more performant and stable than HTTP/1.1, specially for concurrent requests
|
httpx ~= 0.23.3
|
||||||
httpx[http2] ~= 0.23.3
|
|
||||||
|
|
|
@ -92,12 +92,14 @@ from telegram._utils.argumentparsing import parse_sequence_arg
|
||||||
from telegram._utils.defaultvalue import DEFAULT_NONE, DefaultValue
|
from telegram._utils.defaultvalue import DEFAULT_NONE, DefaultValue
|
||||||
from telegram._utils.files import is_local_file, parse_file_input
|
from telegram._utils.files import is_local_file, parse_file_input
|
||||||
from telegram._utils.types import DVInput, FileInput, JSONDict, ODVInput, ReplyMarkup
|
from telegram._utils.types import DVInput, FileInput, JSONDict, ODVInput, ReplyMarkup
|
||||||
|
from telegram._utils.warnings import warn
|
||||||
from telegram._webhookinfo import WebhookInfo
|
from telegram._webhookinfo import WebhookInfo
|
||||||
from telegram.constants import InlineQueryLimit
|
from telegram.constants import InlineQueryLimit
|
||||||
from telegram.error import InvalidToken
|
from telegram.error import InvalidToken
|
||||||
from telegram.request import BaseRequest, RequestData
|
from telegram.request import BaseRequest, RequestData
|
||||||
from telegram.request._httpxrequest import HTTPXRequest
|
from telegram.request._httpxrequest import HTTPXRequest
|
||||||
from telegram.request._requestparameter import RequestParameter
|
from telegram.request._requestparameter import RequestParameter
|
||||||
|
from telegram.warnings import PTBUserWarning
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from telegram import (
|
from telegram import (
|
||||||
|
@ -241,6 +243,38 @@ class Bot(TelegramObject, AsyncContextManager["Bot"]):
|
||||||
HTTPXRequest() if request is None else request,
|
HTTPXRequest() if request is None else request,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# this section is about issuing a warning when using HTTP/2 and connect to a self hosted
|
||||||
|
# bot api instance, which currently only supports HTTP/1.1. Checking if a custom base url
|
||||||
|
# is set is the best way to do that.
|
||||||
|
|
||||||
|
warning_string = ""
|
||||||
|
|
||||||
|
if (
|
||||||
|
isinstance(self._request[0], HTTPXRequest)
|
||||||
|
and self._request[0].http_version == "2"
|
||||||
|
and not base_url.startswith("https://api.telegram.org/bot")
|
||||||
|
):
|
||||||
|
warning_string = "get_updates_request"
|
||||||
|
|
||||||
|
if (
|
||||||
|
isinstance(self._request[1], HTTPXRequest)
|
||||||
|
and self._request[1].http_version == "2"
|
||||||
|
and not base_url.startswith("https://api.telegram.org/bot")
|
||||||
|
):
|
||||||
|
if warning_string:
|
||||||
|
warning_string += " and request"
|
||||||
|
else:
|
||||||
|
warning_string = "request"
|
||||||
|
|
||||||
|
if warning_string:
|
||||||
|
warn(
|
||||||
|
f"You set the HTTP version for the {warning_string} HTTPXRequest instance to "
|
||||||
|
f"HTTP/2. The self hosted bot api instances only support HTTP/1.1. You should "
|
||||||
|
f"either run a HTTP proxy in front of it which supports HTTP/2 or use HTTP/1.1.",
|
||||||
|
PTBUserWarning,
|
||||||
|
stacklevel=2,
|
||||||
|
)
|
||||||
|
|
||||||
if private_key:
|
if private_key:
|
||||||
if not CRYPTO_INSTALLED:
|
if not CRYPTO_INSTALLED:
|
||||||
raise RuntimeError(
|
raise RuntimeError(
|
||||||
|
|
|
@ -178,7 +178,7 @@ class ApplicationBuilder(Generic[BT, CCT, UD, CD, BD, JQ]):
|
||||||
self._get_updates_write_timeout: ODVInput[float] = DEFAULT_NONE
|
self._get_updates_write_timeout: ODVInput[float] = DEFAULT_NONE
|
||||||
self._get_updates_pool_timeout: ODVInput[float] = DEFAULT_NONE
|
self._get_updates_pool_timeout: ODVInput[float] = DEFAULT_NONE
|
||||||
self._get_updates_request: DVInput["BaseRequest"] = DEFAULT_NONE
|
self._get_updates_request: DVInput["BaseRequest"] = DEFAULT_NONE
|
||||||
self._get_updates_http_version: DVInput[str] = DefaultValue("2")
|
self._get_updates_http_version: DVInput[str] = DefaultValue("1.1")
|
||||||
self._private_key: ODVInput[bytes] = DEFAULT_NONE
|
self._private_key: ODVInput[bytes] = DEFAULT_NONE
|
||||||
self._private_key_password: ODVInput[bytes] = DEFAULT_NONE
|
self._private_key_password: ODVInput[bytes] = DEFAULT_NONE
|
||||||
self._defaults: ODVInput["Defaults"] = DEFAULT_NONE
|
self._defaults: ODVInput["Defaults"] = DEFAULT_NONE
|
||||||
|
@ -204,7 +204,7 @@ class ApplicationBuilder(Generic[BT, CCT, UD, CD, BD, JQ]):
|
||||||
self._post_shutdown: Optional[Callable[[Application], Coroutine[Any, Any, None]]] = None
|
self._post_shutdown: Optional[Callable[[Application], Coroutine[Any, Any, None]]] = None
|
||||||
self._post_stop: Optional[Callable[[Application], Coroutine[Any, Any, None]]] = None
|
self._post_stop: Optional[Callable[[Application], Coroutine[Any, Any, None]]] = None
|
||||||
self._rate_limiter: ODVInput["BaseRateLimiter"] = DEFAULT_NONE
|
self._rate_limiter: ODVInput["BaseRateLimiter"] = DEFAULT_NONE
|
||||||
self._http_version: DVInput[str] = DefaultValue("2")
|
self._http_version: DVInput[str] = DefaultValue("1.1")
|
||||||
|
|
||||||
def _build_request(self, get_updates: bool) -> BaseRequest:
|
def _build_request(self, get_updates: bool) -> BaseRequest:
|
||||||
prefix = "_get_updates_" if get_updates else "_"
|
prefix = "_get_updates_" if get_updates else "_"
|
||||||
|
@ -232,7 +232,7 @@ class ApplicationBuilder(Generic[BT, CCT, UD, CD, BD, JQ]):
|
||||||
key: value for key, value in timeouts.items() if not isinstance(value, DefaultValue)
|
key: value for key, value in timeouts.items() if not isinstance(value, DefaultValue)
|
||||||
}
|
}
|
||||||
|
|
||||||
http_version = DefaultValue.get_value(getattr(self, f"{prefix}http_version")) or "2"
|
http_version = DefaultValue.get_value(getattr(self, f"{prefix}http_version")) or "1.1"
|
||||||
|
|
||||||
return HTTPXRequest(
|
return HTTPXRequest(
|
||||||
connection_pool_size=connection_pool_size,
|
connection_pool_size=connection_pool_size,
|
||||||
|
@ -564,15 +564,32 @@ class ApplicationBuilder(Generic[BT, CCT, UD, CD, BD, JQ]):
|
||||||
def http_version(self: BuilderType, http_version: str) -> BuilderType:
|
def http_version(self: BuilderType, http_version: str) -> BuilderType:
|
||||||
"""Sets the HTTP protocol version which is used for the
|
"""Sets the HTTP protocol version which is used for the
|
||||||
:paramref:`~telegram.request.HTTPXRequest.http_version` parameter of
|
:paramref:`~telegram.request.HTTPXRequest.http_version` parameter of
|
||||||
:attr:`telegram.Bot.request`. By default, HTTP/2 is used.
|
:attr:`telegram.Bot.request`. By default, HTTP/1.1 is used.
|
||||||
|
|
||||||
.. seealso:: :meth:`get_updates_http_version`
|
.. seealso:: :meth:`get_updates_http_version`
|
||||||
|
|
||||||
|
Note:
|
||||||
|
Users have observed stability issues with HTTP/2, which happen due to how the `h2
|
||||||
|
library handles <https://github.com/python-hyper/h2/issues/1181>` cancellations of
|
||||||
|
keepalive connections. See `#3556 <https://github.com/python-telegram-bot/
|
||||||
|
python-telegram-bot/issues/3556>`_ for a discussion.
|
||||||
|
|
||||||
|
If you want to use HTTP/2, you must install PTB with the optional requirement
|
||||||
|
``http2``, i.e.
|
||||||
|
.. code-block:: bash
|
||||||
|
|
||||||
|
pip install python-telegram-bot[http2]
|
||||||
|
|
||||||
|
Keep in mind that the HTTP/1.1 implementation may be considered the `"more
|
||||||
|
robust option at this time" <https://www.python-httpx.org/http2#enabling-http2>`_.
|
||||||
|
|
||||||
.. versionadded:: 20.1
|
.. versionadded:: 20.1
|
||||||
|
.. versionchanged:: NEXT.VERSION
|
||||||
|
Reset the default version to 1.1.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
http_version (:obj:`str`): Pass ``"1.1"`` if you'd like to use HTTP/1.1 for making
|
http_version (:obj:`str`): Pass ``"2"`` if you'd like to use HTTP/2 for making
|
||||||
requests to Telegram. Defaults to ``"2"``, in which case HTTP/2 is used.
|
requests to Telegram. Defaults to ``"1.1"``, in which case HTTP/1.1 is used.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
:class:`ApplicationBuilder`: The same builder with the updated argument.
|
:class:`ApplicationBuilder`: The same builder with the updated argument.
|
||||||
|
@ -705,15 +722,31 @@ class ApplicationBuilder(Generic[BT, CCT, UD, CD, BD, JQ]):
|
||||||
def get_updates_http_version(self: BuilderType, get_updates_http_version: str) -> BuilderType:
|
def get_updates_http_version(self: BuilderType, get_updates_http_version: str) -> BuilderType:
|
||||||
"""Sets the HTTP protocol version which is used for the
|
"""Sets the HTTP protocol version which is used for the
|
||||||
:paramref:`~telegram.request.HTTPXRequest.http_version` parameter which is used in the
|
:paramref:`~telegram.request.HTTPXRequest.http_version` parameter which is used in the
|
||||||
:meth:`telegram.Bot.get_updates` request. By default, HTTP/2 is used.
|
:meth:`telegram.Bot.get_updates` request. By default, HTTP/1.1 is used.
|
||||||
|
|
||||||
.. seealso:: :meth:`http_version`
|
.. seealso:: :meth:`http_version`
|
||||||
|
|
||||||
|
Note:
|
||||||
|
Users have observed stability issues with HTTP/2, which happen due to how the `h2
|
||||||
|
library handles <https://github.com/python-hyper/h2/issues/1181>` cancellations of
|
||||||
|
keepalive connections. See `#3556 <https://github.com/python-telegram-bot/
|
||||||
|
python-telegram-bot/issues/3556>`_ for a discussion.
|
||||||
|
|
||||||
|
You will also need to install the http2 dependency. Keep in mind that the HTTP/1.1
|
||||||
|
implementation may be considered the `"more robust option at this time"
|
||||||
|
<https://www.python-httpx.org/http2#enabling-http2>`_.
|
||||||
|
|
||||||
|
.. code-block:: bash
|
||||||
|
|
||||||
|
pip install httpx[http2]
|
||||||
|
|
||||||
.. versionadded:: 20.1
|
.. versionadded:: 20.1
|
||||||
|
.. versionchanged:: NEXT.VERSION
|
||||||
|
Reset the default version to 1.1.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
get_updates_http_version (:obj:`str`): Pass ``"1.1"`` if you'd like to use HTTP/1.1 for
|
get_updates_http_version (:obj:`str`): Pass ``"2"`` if you'd like to use HTTP/2 for
|
||||||
making requests to Telegram. Defaults to ``"2"``, in which case HTTP/2 is used.
|
making requests to Telegram. Defaults to ``"1.1"``, in which case HTTP/1.1 is used.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
:class:`ApplicationBuilder`: The same builder with the updated argument.
|
:class:`ApplicationBuilder`: The same builder with the updated argument.
|
||||||
|
|
|
@ -82,14 +82,16 @@ class HTTPXRequest(BaseRequest):
|
||||||
With a finite pool timeout, you must expect :exc:`telegram.error.TimedOut`
|
With a finite pool timeout, you must expect :exc:`telegram.error.TimedOut`
|
||||||
exceptions to be thrown when more requests are made simultaneously than there are
|
exceptions to be thrown when more requests are made simultaneously than there are
|
||||||
connections in the connection pool!
|
connections in the connection pool!
|
||||||
http_version (:obj:`str`, optional): If ``"1.1"``, HTTP/1.1 will be used instead of HTTP/2.
|
http_version (:obj:`str`, optional): If ``"2"``, HTTP/2 will be used instead of HTTP/1.1.
|
||||||
Defaults to ``"2"``.
|
Defaults to ``"1.1"``.
|
||||||
|
|
||||||
.. versionadded:: 20.1
|
.. versionadded:: 20.1
|
||||||
|
.. versionchanged:: NEXT.VERSION
|
||||||
|
Reset the default version to 1.1.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
__slots__ = ("_client", "_client_kwargs")
|
__slots__ = ("_client", "_client_kwargs", "_http_version")
|
||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
|
@ -99,8 +101,9 @@ class HTTPXRequest(BaseRequest):
|
||||||
write_timeout: Optional[float] = 5.0,
|
write_timeout: Optional[float] = 5.0,
|
||||||
connect_timeout: Optional[float] = 5.0,
|
connect_timeout: Optional[float] = 5.0,
|
||||||
pool_timeout: Optional[float] = 1.0,
|
pool_timeout: Optional[float] = 1.0,
|
||||||
http_version: str = "2",
|
http_version: str = "1.1",
|
||||||
):
|
):
|
||||||
|
self._http_version = http_version
|
||||||
timeout = httpx.Timeout(
|
timeout = httpx.Timeout(
|
||||||
connect=connect_timeout,
|
connect=connect_timeout,
|
||||||
read=read_timeout,
|
read=read_timeout,
|
||||||
|
@ -130,13 +133,27 @@ class HTTPXRequest(BaseRequest):
|
||||||
try:
|
try:
|
||||||
self._client = self._build_client()
|
self._client = self._build_client()
|
||||||
except ImportError as exc:
|
except ImportError as exc:
|
||||||
if "httpx[socks]" not in str(exc):
|
if "httpx[http2]" not in str(exc) and "httpx[socks]" not in str(exc):
|
||||||
raise exc
|
raise exc
|
||||||
|
|
||||||
|
if "httpx[socks]" in str(exc):
|
||||||
raise RuntimeError(
|
raise RuntimeError(
|
||||||
"To use Socks5 proxies, PTB must be installed via `pip install "
|
"To use Socks5 proxies, PTB must be installed via `pip install "
|
||||||
"python-telegram-bot[socks]`."
|
"python-telegram-bot[socks]`."
|
||||||
) from exc
|
) from exc
|
||||||
|
raise RuntimeError(
|
||||||
|
"To use HTTP/2, PTB must be installed via `pip install "
|
||||||
|
"python-telegram-bot[http2]`."
|
||||||
|
) from exc
|
||||||
|
|
||||||
|
@property
|
||||||
|
def http_version(self) -> str:
|
||||||
|
"""
|
||||||
|
:obj:`str`: Used HTTP version, see :paramref:`http_version`.
|
||||||
|
|
||||||
|
.. versionadded:: NEXT.VERSION
|
||||||
|
"""
|
||||||
|
return self._http_version
|
||||||
|
|
||||||
def _build_client(self) -> httpx.AsyncClient:
|
def _build_client(self) -> httpx.AsyncClient:
|
||||||
return httpx.AsyncClient(**self._client_kwargs) # type: ignore[arg-type]
|
return httpx.AsyncClient(**self._client_kwargs) # type: ignore[arg-type]
|
||||||
|
|
|
@ -118,15 +118,15 @@ class TestApplicationBuilder:
|
||||||
assert get_updates_client.timeout == httpx.Timeout(
|
assert get_updates_client.timeout == httpx.Timeout(
|
||||||
connect=5.0, read=5.0, write=5.0, pool=1.0
|
connect=5.0, read=5.0, write=5.0, pool=1.0
|
||||||
)
|
)
|
||||||
assert not get_updates_client.http1
|
assert get_updates_client.http1 is True
|
||||||
assert get_updates_client.http2 is True
|
assert not get_updates_client.http2
|
||||||
|
|
||||||
client = app.bot.request._client
|
client = app.bot.request._client
|
||||||
assert client.limits == httpx.Limits(max_connections=256, max_keepalive_connections=256)
|
assert client.limits == httpx.Limits(max_connections=256, max_keepalive_connections=256)
|
||||||
assert client.proxies is None
|
assert client.proxies is None
|
||||||
assert client.timeout == httpx.Timeout(connect=5.0, read=5.0, write=5.0, pool=1.0)
|
assert client.timeout == httpx.Timeout(connect=5.0, read=5.0, write=5.0, pool=1.0)
|
||||||
assert not client.http1
|
assert client.http1 is True
|
||||||
assert client.http2 is True
|
assert not client.http2
|
||||||
|
|
||||||
assert isinstance(app.update_queue, asyncio.Queue)
|
assert isinstance(app.update_queue, asyncio.Queue)
|
||||||
assert isinstance(app.updater, Updater)
|
assert isinstance(app.updater, Updater)
|
||||||
|
|
|
@ -74,12 +74,30 @@ async def httpx_request():
|
||||||
@pytest.mark.skipif(
|
@pytest.mark.skipif(
|
||||||
TEST_WITH_OPT_DEPS, reason="Only relevant if the optional dependency is not installed"
|
TEST_WITH_OPT_DEPS, reason="Only relevant if the optional dependency is not installed"
|
||||||
)
|
)
|
||||||
class TestNoSocks:
|
class TestNoSocksHTTP2WithoutRequest:
|
||||||
async def test_init(self, bot):
|
async def test_init(self, bot):
|
||||||
with pytest.raises(RuntimeError, match=r"python-telegram-bot\[socks\]"):
|
with pytest.raises(RuntimeError, match=r"python-telegram-bot\[socks\]"):
|
||||||
HTTPXRequest(proxy_url="socks5://foo")
|
HTTPXRequest(proxy_url="socks5://foo")
|
||||||
|
with pytest.raises(RuntimeError, match=r"python-telegram-bot\[http2\]"):
|
||||||
|
HTTPXRequest(http_version="2")
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.skipif(not TEST_WITH_OPT_DEPS, reason="Optional dependencies not installed")
|
||||||
|
class TestHTTP2WithRequest:
|
||||||
|
async def test_http_2_response(self):
|
||||||
|
httpx_request = HTTPXRequest(http_version="2")
|
||||||
|
async with httpx_request:
|
||||||
|
resp = await httpx_request._client.request(
|
||||||
|
url="https://python-telegram-bot.org",
|
||||||
|
method="GET",
|
||||||
|
headers={"User-Agent": httpx_request.USER_AGENT},
|
||||||
|
)
|
||||||
|
assert resp.http_version == "HTTP/2"
|
||||||
|
|
||||||
|
|
||||||
|
# I picked not TEST_XXX because that's the default, meaning it will run by default for an end-user
|
||||||
|
# who runs pytest.
|
||||||
|
@pytest.mark.skipif(not TEST_WITH_OPT_DEPS, reason="No need to run this twice")
|
||||||
class TestRequestWithoutRequest:
|
class TestRequestWithoutRequest:
|
||||||
test_flag = None
|
test_flag = None
|
||||||
|
|
||||||
|
@ -321,6 +339,7 @@ class TestRequestWithoutRequest:
|
||||||
assert self.test_flag == (1, 2, 3, 4)
|
assert self.test_flag == (1, 2, 3, 4)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.skipif(not TEST_WITH_OPT_DEPS, reason="No need to run this twice")
|
||||||
class TestHTTPXRequestWithoutRequest:
|
class TestHTTPXRequestWithoutRequest:
|
||||||
test_flag = None
|
test_flag = None
|
||||||
|
|
||||||
|
@ -345,7 +364,8 @@ class TestHTTPXRequestWithoutRequest:
|
||||||
assert request._client.limits == httpx.Limits(
|
assert request._client.limits == httpx.Limits(
|
||||||
max_connections=1, max_keepalive_connections=1
|
max_connections=1, max_keepalive_connections=1
|
||||||
)
|
)
|
||||||
assert request._client.http2 is True
|
assert request._client.http1 is True
|
||||||
|
assert not request._client.http2
|
||||||
|
|
||||||
request = HTTPXRequest(
|
request = HTTPXRequest(
|
||||||
connection_pool_size=42,
|
connection_pool_size=42,
|
||||||
|
@ -413,16 +433,6 @@ class TestHTTPXRequestWithoutRequest:
|
||||||
)
|
)
|
||||||
assert resp.http_version == "HTTP/1.1"
|
assert resp.http_version == "HTTP/1.1"
|
||||||
|
|
||||||
async def test_http_2_response(self):
|
|
||||||
httpx_request = HTTPXRequest()
|
|
||||||
async with httpx_request:
|
|
||||||
resp = await httpx_request._client.request(
|
|
||||||
url="https://python-telegram-bot.org",
|
|
||||||
method="GET",
|
|
||||||
headers={"User-Agent": httpx_request.USER_AGENT},
|
|
||||||
)
|
|
||||||
assert resp.http_version == "HTTP/2"
|
|
||||||
|
|
||||||
async def test_do_request_after_shutdown(self, httpx_request):
|
async def test_do_request_after_shutdown(self, httpx_request):
|
||||||
await httpx_request.shutdown()
|
await httpx_request.shutdown()
|
||||||
with pytest.raises(RuntimeError, match="not initialized"):
|
with pytest.raises(RuntimeError, match="not initialized"):
|
||||||
|
@ -592,6 +602,7 @@ class TestHTTPXRequestWithoutRequest:
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.skipif(not TEST_WITH_OPT_DEPS, reason="No need to run this twice")
|
||||||
class TestHTTPXRequestWithRequest:
|
class TestHTTPXRequestWithRequest:
|
||||||
async def test_do_request_wait_for_pool(self, httpx_request):
|
async def test_do_request_wait_for_pool(self, httpx_request):
|
||||||
"""The pool logic is buried rather deeply in httpxcore, so we make actual requests here
|
"""The pool logic is buried rather deeply in httpxcore, so we make actual requests here
|
||||||
|
|
|
@ -1648,6 +1648,33 @@ class TestBotWithoutRequest:
|
||||||
bot.callback_data_cache.clear_callback_data()
|
bot.callback_data_cache.clear_callback_data()
|
||||||
bot.callback_data_cache.clear_callback_queries()
|
bot.callback_data_cache.clear_callback_queries()
|
||||||
|
|
||||||
|
async def test_http2_runtime_error(self, recwarn):
|
||||||
|
Bot("12345:ABCDE", base_url="http://", request=HTTPXRequest(http_version="2"))
|
||||||
|
Bot(
|
||||||
|
"12345:ABCDE",
|
||||||
|
base_url="http://",
|
||||||
|
get_updates_request=HTTPXRequest(http_version="2"),
|
||||||
|
)
|
||||||
|
Bot(
|
||||||
|
"12345:ABCDE",
|
||||||
|
base_url="http://",
|
||||||
|
request=HTTPXRequest(http_version="2"),
|
||||||
|
get_updates_request=HTTPXRequest(http_version="2"),
|
||||||
|
)
|
||||||
|
# this exists to make sure the error is also raised by extbot
|
||||||
|
ExtBot("12345:ABCDE", base_url="http://", request=HTTPXRequest(http_version="2"))
|
||||||
|
assert len(recwarn) == 4
|
||||||
|
assert "You set the HTTP version for the request HTTPXRequest instance" in str(
|
||||||
|
recwarn[0].message
|
||||||
|
)
|
||||||
|
assert "You set the HTTP version for the get_updates_request HTTPXRequest instance" in str(
|
||||||
|
recwarn[1].message
|
||||||
|
)
|
||||||
|
assert (
|
||||||
|
"You set the HTTP version for the get_updates_request and request HTTPXRequest "
|
||||||
|
"instance" in str(recwarn[2].message)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class TestBotWithRequest:
|
class TestBotWithRequest:
|
||||||
"""
|
"""
|
||||||
|
|
Loading…
Reference in a new issue