Skip to content

Commit

Permalink
Addressed bug where recording requests does not save headers to file. C…
Browse files Browse the repository at this point in the history
…loses #715 (#720)
  • Loading branch information
TheJacobWalters authored Jun 14, 2024
1 parent 22fc9e8 commit b0573d2
Show file tree
Hide file tree
Showing 3 changed files with 53 additions and 7 deletions.
7 changes: 6 additions & 1 deletion responses/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -814,7 +814,11 @@ def add(

if adding_headers is not None:
kwargs.setdefault("headers", adding_headers)
if "content_type" in kwargs and "headers" in kwargs:
if (
"content_type" in kwargs
and "headers" in kwargs
and kwargs["headers"] is not None
):
header_keys = [header.lower() for header in kwargs["headers"]]
if "content-type" in header_keys:
raise RuntimeError(
Expand Down Expand Up @@ -852,6 +856,7 @@ def _add_from_file(self, file_path: "Union[str, bytes, os.PathLike[Any]]") -> No
url=rsp["url"],
body=rsp["body"],
status=rsp["status"],
headers=rsp["headers"] if "headers" in rsp else None,
content_type=rsp["content_type"],
auto_calculate_content_length=rsp["auto_calculate_content_length"],
)
Expand Down
30 changes: 29 additions & 1 deletion responses/_recorder.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,29 @@ def _remove_nones(d: "Any") -> "Any":
return d


def _remove_default_headers(data: "Any") -> "Any":
"""
It would be too verbose to store these headers in the file generated by the
record functionality.
"""
if isinstance(data, dict):
keys_to_remove = [
"Content-Length",
"Content-Type",
"Date",
"Server",
"Connection",
"Content-Encoding",
]
for i, response in enumerate(data["responses"]):
for key in keys_to_remove:
if key in response["response"]["headers"]:
del data["responses"][i]["response"]["headers"][key]
if not response["response"]["headers"]:
del data["responses"][i]["response"]["headers"]
return data


def _dump(
registered: "List[BaseResponse]",
destination: "Union[BinaryIO, TextIOWrapper]",
Expand Down Expand Up @@ -63,7 +86,8 @@ def _dump(
"Cannot dump response object."
"Probably you use custom Response object that is missing required attributes"
) from exc
dumper(_remove_nones(data), destination)

dumper(_remove_default_headers(_remove_nones(data)), destination)


class Recorder(RequestsMock):
Expand Down Expand Up @@ -116,11 +140,15 @@ def _on_request(
request.params = self._parse_request_params(request.path_url) # type: ignore[attr-defined]
request.req_kwargs = kwargs # type: ignore[attr-defined]
requests_response = _real_send(adapter, request, **kwargs)
headers_values = {
key: value for key, value in requests_response.headers.items()
}
responses_response = Response(
method=str(request.method),
url=str(requests_response.request.url),
status=requests_response.status_code,
body=requests_response.text,
headers=headers_values,
)
self._registry.add(responses_response)
return requests_response
Expand Down
23 changes: 18 additions & 5 deletions responses/tests/test_recorder.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ def get_data(host, port):
"response": {
"method": "GET",
"url": f"http://{host}:{port}/404",
"headers": {"x": "foo"},
"body": "404 Not Found",
"status": 404,
"content_type": "text/plain",
Expand All @@ -33,6 +34,7 @@ def get_data(host, port):
"response": {
"method": "GET",
"url": f"http://{host}:{port}/status/wrong",
"headers": {"x": "foo"},
"body": "Invalid status code",
"status": 400,
"content_type": "text/plain",
Expand All @@ -43,6 +45,7 @@ def get_data(host, port):
"response": {
"method": "GET",
"url": f"http://{host}:{port}/500",
"headers": {"x": "foo"},
"body": "500 Internal Server Error",
"status": 500,
"content_type": "text/plain",
Expand Down Expand Up @@ -89,7 +92,6 @@ def run():

with open(self.out_file) as file:
data = yaml.safe_load(file)

assert data == get_data(httpserver.host, httpserver.port)

def test_recorder_toml(self, httpserver):
Expand Down Expand Up @@ -122,16 +124,27 @@ def run():

def prepare_server(self, httpserver):
httpserver.expect_request("/500").respond_with_data(
"500 Internal Server Error", status=500, content_type="text/plain"
"500 Internal Server Error",
status=500,
content_type="text/plain",
headers={"x": "foo"},
)
httpserver.expect_request("/202").respond_with_data(
"OK", status=202, content_type="text/plain"
"OK",
status=202,
content_type="text/plain",
)
httpserver.expect_request("/404").respond_with_data(
"404 Not Found", status=404, content_type="text/plain"
"404 Not Found",
status=404,
content_type="text/plain",
headers={"x": "foo"},
)
httpserver.expect_request("/status/wrong").respond_with_data(
"Invalid status code", status=400, content_type="text/plain"
"Invalid status code",
status=400,
content_type="text/plain",
headers={"x": "foo"},
)
url500 = httpserver.url_for("/500")
url202 = httpserver.url_for("/202")
Expand Down

0 comments on commit b0573d2

Please sign in to comment.