Skip to content

Commit

Permalink
Release 3.11.3 (#188)
Browse files Browse the repository at this point in the history
3.11.3 (2024-12-13)
-------------------

**Fixed**
- Static type checker getting confused around ``AsyncSession`` and
attached overloads (``AsyncResponse`` or ``Response``). (#185)

**Changed**
- Default keepalive (HTTP/2, and HTTP/3) changed to 1 hour. In
conformance with urllib3-future.

**Removed**
- Automatic resolution of pending lazy responses if there are too many
of them.
Previously, we hardcoded a limit of 128 * NUM_CONN_POOL maximum inflight
(aka. unresolved/lazy) response.
This was unrealistic due to a number of factors like (but not limited
to):
  A) remote peers can choose at will the max streams.
  B) we can have multiple pool with multiple (varying) max capacities.
C) retrieving max streams per pool per conn is a very costly procedure
(in terms of performance).
We will revisit this later on. You still can set
``max_in_flight_multiplexed`` in your ``HTTPAdapter`` to
  restore this broken behavior.
  • Loading branch information
Ousret authored Dec 13, 2024
2 parents 7036130 + 1fbedfa commit 6bf7791
Show file tree
Hide file tree
Showing 17 changed files with 84 additions and 52 deletions.
17 changes: 17 additions & 0 deletions .coveragerc
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,20 @@ source =
src/niquests
*/niquests
*\niquests

[report]
omit =
src/niquests/help.py

exclude_lines =
except ModuleNotFoundError:
except ImportError:
pass
import
raise NotImplementedError
.* # Platform-specific.*
.*:.* # Python \d.*
.* # Abstract
.* # Defensive:
if (?:typing.)?TYPE_CHECKING:
^\s*?\.\.\.\s*$
19 changes: 19 additions & 0 deletions HISTORY.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,25 @@
Release History
===============

3.11.3 (2024-12-13)
-------------------

**Fixed**
- Static type checker getting confused around ``AsyncSession`` and attached overloads (``AsyncResponse`` or ``Response``). (#185)

**Changed**
- Default keepalive (HTTP/2, and HTTP/3) changed to 1 hour. In conformance with urllib3-future.

**Removed**
- Automatic resolution of pending lazy responses if there are too many of them.
Previously, we hardcoded a limit of 128 * NUM_CONN_POOL maximum inflight (aka. unresolved/lazy) response.
This was unrealistic due to a number of factors like (but not limited to):
A) remote peers can choose at will the max streams.
B) we can have multiple pool with multiple (varying) max capacities.
C) retrieving max streams per pool per conn is a very costly procedure (in terms of performance).
We will revisit this later on. You still can set ``max_in_flight_multiplexed`` in your ``HTTPAdapter`` to
restore this broken behavior.

3.11.2 (2024-11-29)
-------------------

Expand Down
5 changes: 4 additions & 1 deletion noxfile.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,10 @@ def tests_impl(
"--strict-config",
"--strict-markers",
*(session.posargs or ("tests/",)),
env={"PYTHONWARNINGS": "always::DeprecationWarning"},
env={
"PYTHONWARNINGS": "always::DeprecationWarning",
"NIQUESTS_STRICT_OCSP": "1",
},
)


Expand Down
2 changes: 1 addition & 1 deletion requirements-dev.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
-e .[socks]
pytest>=2.8.0,<=7.4.4
pytest-cov
coverage>=7.2.7,<7.7
pytest-httpbin>=2,<3
pytest-asyncio>=0.21.1,<1.0
httpbin==0.10.2
Expand Down
4 changes: 2 additions & 2 deletions src/niquests/__version__.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,9 @@
__url__: str = "https://niquests.readthedocs.io"

__version__: str
__version__ = "3.11.2"
__version__ = "3.11.3"

__build__: int = 0x031102
__build__: int = 0x031103
__author__: str = "Kenneth Reitz"
__author_email__: str = "[email protected]"
__license__: str = "Apache-2.0"
Expand Down
33 changes: 16 additions & 17 deletions src/niquests/_async.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
from urllib3 import ConnectionInfo
from urllib3.contrib.resolver._async import AsyncBaseResolver
from urllib3.contrib.webextensions._async import load_extension
else:
else: # Defensive: tested in separate/isolated CI
from urllib3_future import ConnectionInfo # type: ignore[assignment]
from urllib3_future.contrib.resolver._async import AsyncBaseResolver # type: ignore[assignment]
from urllib3_future.contrib.webextensions._async import load_extension # type: ignore[assignment]
Expand Down Expand Up @@ -130,7 +130,7 @@ def __init__(
pool_connections: int = DEFAULT_POOLSIZE,
pool_maxsize: int = DEFAULT_POOLSIZE,
happy_eyeballs: bool | int = False,
keepalive_delay: float | int | None = 300.0,
keepalive_delay: float | int | None = 3600.0,
keepalive_idle_window: float | int | None = 60.0,
base_url: str | None = None,
):
Expand Down Expand Up @@ -290,10 +290,10 @@ def __enter__(self) -> typing.NoReturn:
'You probably meant "async with". Did you forget to prepend the "async" keyword?'
)

async def __aenter__(self):
async def __aenter__(self) -> AsyncSession:
return self

async def __aexit__(self, exc, value, tb):
async def __aexit__(self, exc, value, tb) -> None:
await self.close()

def mount(self, prefix: str, adapter: AsyncBaseAdapter) -> None: # type: ignore[override]
Expand Down Expand Up @@ -770,7 +770,7 @@ async def request(
allow_redirects: bool = ...,
proxies: ProxyType | None = ...,
hooks: HookType[PreparedRequest | Response] | None = ...,
stream: Literal[False] = ...,
stream: Literal[False] | None = ...,
verify: TLSVerifyType | None = ...,
cert: TLSClientCertType | None = ...,
json: typing.Any | None = ...,
Expand All @@ -791,8 +791,7 @@ async def request(
allow_redirects: bool = ...,
proxies: ProxyType | None = ...,
hooks: HookType[PreparedRequest | Response] | None = ...,
*,
stream: Literal[True],
stream: Literal[True] = ...,
verify: TLSVerifyType | None = ...,
cert: TLSClientCertType | None = ...,
json: typing.Any | None = ...,
Expand All @@ -812,7 +811,7 @@ async def request( # type: ignore[override]
allow_redirects: bool = True,
proxies: ProxyType | None = None,
hooks: HookType[PreparedRequest | Response] | None = None,
stream: bool = False,
stream: bool | None = None,
verify: TLSVerifyType | None = None,
cert: TLSClientCertType | None = None,
json: typing.Any | None = None,
Expand Down Expand Up @@ -880,7 +879,7 @@ async def get(
proxies: ProxyType | None = ...,
hooks: HookType[PreparedRequest | Response] | None = ...,
verify: TLSVerifyType = ...,
stream: Literal[False] | Literal[None] = ...,
stream: Literal[False] | None = ...,
cert: TLSClientCertType | None = ...,
**kwargs: typing.Any,
) -> Response: ...
Expand All @@ -899,7 +898,7 @@ async def get(
proxies: ProxyType | None = ...,
hooks: HookType[PreparedRequest | Response] | None = ...,
verify: TLSVerifyType = ...,
stream: Literal[True],
stream: Literal[True] = ...,
cert: TLSClientCertType | None = ...,
**kwargs: typing.Any,
) -> AsyncResponse: ...
Expand Down Expand Up @@ -933,7 +932,7 @@ async def get( # type: ignore[override]
proxies=proxies,
hooks=hooks,
verify=verify,
stream=stream,
stream=stream, # type: ignore[arg-type]
cert=cert,
**kwargs,
)
Expand Down Expand Up @@ -1005,7 +1004,7 @@ async def options( # type: ignore[override]
proxies=proxies,
hooks=hooks,
verify=verify,
stream=stream,
stream=stream, # type: ignore[arg-type]
cert=cert,
**kwargs,
)
Expand Down Expand Up @@ -1077,7 +1076,7 @@ async def head( # type: ignore[override]
proxies=proxies,
hooks=hooks,
verify=verify,
stream=stream,
stream=stream, # type: ignore[arg-type]
cert=cert,
**kwargs,
)
Expand Down Expand Up @@ -1158,7 +1157,7 @@ async def post( # type: ignore[override]
proxies=proxies,
hooks=hooks,
verify=verify,
stream=stream,
stream=stream, # type: ignore[arg-type]
cert=cert,
)

Expand Down Expand Up @@ -1238,7 +1237,7 @@ async def put( # type: ignore[override]
proxies=proxies,
hooks=hooks,
verify=verify,
stream=stream,
stream=stream, # type: ignore[arg-type]
cert=cert,
)

Expand Down Expand Up @@ -1318,7 +1317,7 @@ async def patch( # type: ignore[override]
proxies=proxies,
hooks=hooks,
verify=verify,
stream=stream,
stream=stream, # type: ignore[arg-type]
cert=cert,
)

Expand Down Expand Up @@ -1389,7 +1388,7 @@ async def delete( # type: ignore[override]
proxies=proxies,
hooks=hooks,
verify=verify,
stream=stream,
stream=stream, # type: ignore[arg-type]
cert=cert,
**kwargs,
)
Expand Down
2 changes: 1 addition & 1 deletion src/niquests/_typing.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
from urllib3.contrib.resolver import BaseResolver
from urllib3.contrib.resolver._async import AsyncBaseResolver
from urllib3.fields import RequestField
else:
else: # Defensive: tested in separate/isolated CI
from urllib3_future import ( # type: ignore[assignment]
Retry,
Timeout,
Expand Down
22 changes: 7 additions & 15 deletions src/niquests/adapters.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@
from urllib3.contrib.webextensions._async import (
load_extension as async_load_extension,
)
else:
else: # Defensive: tested in separate/isolated CI
from urllib3_future import ( # type: ignore[assignment]
ConnectionInfo,
HTTPConnectionPool,
Expand Down Expand Up @@ -354,7 +354,7 @@ def __init__(
disable_ipv4: bool = False,
disable_ipv6: bool = False,
happy_eyeballs: bool | int = False,
keepalive_delay: float | int | None = 300.0,
keepalive_delay: float | int | None = 3600.0,
keepalive_idle_window: float | int | None = 60.0,
):
if isinstance(max_retries, bool):
Expand Down Expand Up @@ -393,11 +393,7 @@ def __init__(
#: we keep a list of pending (lazy) response
self._promises: dict[str, Response] = {}
self._orphaned: list[BaseHTTPResponse] = []
self._max_in_flight_multiplexed = (
max_in_flight_multiplexed
if max_in_flight_multiplexed is not None
else self._pool_connections * 124
)
self._max_in_flight_multiplexed = max_in_flight_multiplexed
self._promise_lock = RLock()

disabled_svn = set()
Expand Down Expand Up @@ -871,7 +867,7 @@ def send(
), "Tried to send a non-initialized PreparedRequest"

# We enforce a limit to avoid burning out our connection pool.
if multiplexed:
if multiplexed and self._max_in_flight_multiplexed is not None:
with self._promise_lock:
if len(self._promises) >= self._max_in_flight_multiplexed:
self.gather()
Expand Down Expand Up @@ -1447,7 +1443,7 @@ def __init__(
disable_ipv4: bool = False,
disable_ipv6: bool = False,
happy_eyeballs: bool | int = False,
keepalive_delay: float | int | None = 300.0,
keepalive_delay: float | int | None = 3600.0,
keepalive_idle_window: float | int | None = 60.0,
):
if isinstance(max_retries, bool):
Expand Down Expand Up @@ -1487,11 +1483,7 @@ def __init__(
#: we keep a list of pending (lazy) response
self._promises: dict[str, Response | AsyncResponse] = {}
self._orphaned: list[BaseAsyncHTTPResponse] = []
self._max_in_flight_multiplexed = (
max_in_flight_multiplexed
if max_in_flight_multiplexed is not None
else self._pool_connections * 250
)
self._max_in_flight_multiplexed = max_in_flight_multiplexed

disabled_svn = set()

Expand Down Expand Up @@ -1960,7 +1952,7 @@ async def send(
), "Tried to send a non-initialized PreparedRequest"

# We enforce a limit to avoid burning out our connection pool.
if multiplexed:
if multiplexed and self._max_in_flight_multiplexed is not None:
if len(self._promises) >= self._max_in_flight_multiplexed:
await self.gather()

Expand Down
2 changes: 1 addition & 1 deletion src/niquests/cookies.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@

if HAS_LEGACY_URLLIB3 is False:
from urllib3 import BaseHTTPResponse
else:
else: # Defensive: tested in separate/isolated CI
from urllib3_future import BaseHTTPResponse # type: ignore[assignment]

if typing.TYPE_CHECKING:
Expand Down
2 changes: 1 addition & 1 deletion src/niquests/exceptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@

if HAS_LEGACY_URLLIB3 is False:
from urllib3.exceptions import HTTPError as BaseHTTPError
else:
else: # Defensive: tested in separate/isolated CI
from urllib3_future.exceptions import HTTPError as BaseHTTPError # type: ignore

if typing.TYPE_CHECKING:
Expand Down
5 changes: 3 additions & 2 deletions src/niquests/extensions/_async_ocsp.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
from urllib3.util.url import parse_url
from urllib3.contrib.resolver._async import AsyncBaseResolver
from urllib3.contrib.ssa import AsyncSocket
else:
else: # Defensive: tested in separate/isolated CI
from urllib3_future import ConnectionInfo # type: ignore[assignment]
from urllib3_future.exceptions import SecurityWarning # type: ignore[assignment]
from urllib3_future.util.url import parse_url # type: ignore[assignment]
Expand Down Expand Up @@ -383,7 +383,8 @@ async def verify(
resolver=resolver, happy_eyeballs=happy_eyeballs
) as session:
session.trust_env = False
session.proxies = proxies
if proxies:
session.proxies = proxies

# When using Python native capabilities, you won't have the issuerCA DER by default (Python 3.7 to 3.9).
# Unfortunately! But no worries, we can circumvent it! (Python 3.10+ is not concerned anymore)
Expand Down
5 changes: 3 additions & 2 deletions src/niquests/extensions/_ocsp.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
from urllib3.exceptions import SecurityWarning
from urllib3.util.url import parse_url
from urllib3.contrib.resolver import BaseResolver
else:
else: # Defensive: tested in separate/isolated CI
from urllib3_future import ConnectionInfo # type: ignore[assignment]
from urllib3_future.exceptions import SecurityWarning # type: ignore[assignment]
from urllib3_future.util.url import parse_url # type: ignore[assignment]
Expand Down Expand Up @@ -376,7 +376,8 @@ def verify(

with Session(resolver=resolver, happy_eyeballs=happy_eyeballs) as session:
session.trust_env = False
session.proxies = proxies
if proxies:
session.proxies = proxies

# When using Python native capabilities, you won't have the issuerCA DER by default.
# Unfortunately! But no worries, we can circumvent it!
Expand Down
2 changes: 1 addition & 1 deletion src/niquests/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@
RawExtensionFromHTTP,
ServerSideEventExtensionFromHTTP,
)
else:
else: # Defensive: tested in separate/isolated CI
from urllib3_future import ( # type: ignore[assignment]
BaseHTTPResponse,
AsyncHTTPResponse as BaseAsyncHTTPResponse,
Expand Down
8 changes: 4 additions & 4 deletions src/niquests/sessions.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
if HAS_LEGACY_URLLIB3 is False:
from urllib3 import ConnectionInfo
from urllib3.contrib.webextensions import load_extension
else:
else: # Defensive: tested in separate/isolated CI
from urllib3_future import ConnectionInfo # type: ignore[assignment]
from urllib3_future.contrib.webextensions import load_extension # type: ignore[assignment]

Expand Down Expand Up @@ -251,7 +251,7 @@ def __init__(
pool_connections: int = DEFAULT_POOLSIZE,
pool_maxsize: int = DEFAULT_POOLSIZE,
happy_eyeballs: bool | int = False,
keepalive_delay: float | int | None = 300.0,
keepalive_delay: float | int | None = 3600.0,
keepalive_idle_window: float | int | None = 60.0,
base_url: str | None = None,
):
Expand Down Expand Up @@ -425,10 +425,10 @@ def __init__(
),
)

def __enter__(self):
def __enter__(self) -> Session:
return self

def __exit__(self, *args):
def __exit__(self, *args) -> None:
self.close()

def prepare_request(self, request: Request) -> PreparedRequest:
Expand Down
Loading

0 comments on commit 6bf7791

Please sign in to comment.