Skip to content

Commit

Permalink
🐛 Fix compatibility with some third-party mock tools (#45)
Browse files Browse the repository at this point in the history
  • Loading branch information
Ousret authored Nov 15, 2023
1 parent e5b90f5 commit 0058bcf
Show file tree
Hide file tree
Showing 6 changed files with 38 additions and 15 deletions.
9 changes: 9 additions & 0 deletions HISTORY.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,15 @@
Release History
===============

3.2.4 (2023-11-15)
------------------

**Fixed**
- Compatibility with some third-party mock tools.

**Changed**
- Relax IllegalHeader constraint when value is an integer, or float.

3.2.3 (2023-11-11)
------------------

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.2.3"
__version__ = "3.2.4"

__build__: int = 0x030203
__build__: int = 0x030204
__author__: str = "Kenneth Reitz"
__author_email__: str = "[email protected]"
__license__: str = "Apache-2.0"
Expand Down
10 changes: 5 additions & 5 deletions src/niquests/adapters.py
Original file line number Diff line number Diff line change
Expand Up @@ -442,7 +442,7 @@ def build_response(
"""
response = Response()

if isinstance(resp, BaseHTTPResponse):
if isinstance(resp, ResponsePromise) is False:
# Fallback to None if there's no status_code, for whatever reason.
response.status_code = getattr(resp, "status", None)

Expand All @@ -451,19 +451,19 @@ def build_response(

# Set encoding.
response.encoding = get_encoding_from_headers(response.headers)
response.raw = resp
response.reason = response.raw.reason
response.raw = resp # type: ignore[assignment]
response.reason = response.raw.reason # type: ignore[union-attr]

if isinstance(req.url, bytes):
response.url = req.url.decode("utf-8")
else:
response.url = req.url

# Add new cookies from the server.
extract_cookies_to_jar(response.cookies, req, resp)
extract_cookies_to_jar(response.cookies, req, resp) # type: ignore[arg-type]
else:
with self._promise_lock:
self._promises[resp.uid] = response
self._promises[resp.uid] = response # type: ignore[union-attr]

# Give the Response some context.
response.request = req
Expand Down
6 changes: 3 additions & 3 deletions src/niquests/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -832,7 +832,7 @@ class Response:
server's response to an HTTP request.
"""

__attrs__ = {
__attrs__ = [
"_content",
"status_code",
"headers",
Expand All @@ -843,7 +843,7 @@ class Response:
"cookies",
"elapsed",
"request",
}
]

__lazy_attrs__ = {
"json",
Expand Down Expand Up @@ -934,7 +934,7 @@ def lazy(self) -> bool:
Determine if response isn't received and is actually a placeholder.
Only significant if request was sent through a multiplexed connection.
"""
return self.raw is None and hasattr(self, "_gather")
return hasattr(self, "raw") and self.raw is None and hasattr(self, "_gather")

def __getattribute__(self, item):
if item in Response.__lazy_attrs__ and self.lazy:
Expand Down
22 changes: 18 additions & 4 deletions src/niquests/structures.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,24 @@
from .exceptions import InvalidHeader


def _ensure_str_or_bytes(key: typing.Any, value: typing.Any) -> None:
def _ensure_str_or_bytes(
key: typing.Any, value: typing.Any
) -> tuple[bytes | str, bytes | str]:
if isinstance(
value,
(
float,
int,
),
):
if isinstance(key, bytes):
key = key.decode()
value = str(value)
if isinstance(key, (bytes, str)) is False or (
value is not None and isinstance(value, (bytes, str)) is False
):
raise InvalidHeader(f"Illegal header name or value {key}")
return key, value


class CaseInsensitiveDict(MutableMapping):
Expand Down Expand Up @@ -55,14 +68,15 @@ def __init__(self, data=None, **kwargs) -> None:
] = OrderedDict()
if data is None:
data = {}
normalized_items = []
for k, v in data.items() if hasattr(data, "items") else data:
_ensure_str_or_bytes(k, v)
self.update(data, **kwargs)
normalized_items.append(_ensure_str_or_bytes(k, v))
self.update(normalized_items, **kwargs)

def __setitem__(self, key: str | bytes, value: str | bytes) -> None:
# Use the lowercased key for lookups, but store the actual
# key alongside the value.
_ensure_str_or_bytes(key, value)
key, value = _ensure_str_or_bytes(key, value)
self._store[key.lower()] = (key, value)

def __getitem__(self, key) -> bytes | str:
Expand Down
2 changes: 1 addition & 1 deletion tests/test_requests.py
Original file line number Diff line number Diff line change
Expand Up @@ -1666,7 +1666,7 @@ def test_header_validation(self, httpbin):
@pytest.mark.parametrize(
"invalid_header, key",
(
({"foo": 3}, "foo"),
({"foo": ...}, "foo"),
({"bar": {"foo": "bar"}}, "bar"),
({"baz": ["foo", "bar"]}, "baz"),
),
Expand Down

0 comments on commit 0058bcf

Please sign in to comment.