diff --git a/CHANGES/2928.bugfix.rst b/CHANGES/2928.bugfix.rst new file mode 100644 index 00000000000..e763d2b89a2 --- /dev/null +++ b/CHANGES/2928.bugfix.rst @@ -0,0 +1 @@ +Fixed ``Response.text`` raising ``AttributeError`` when ``Response.body`` was set to a string -- by :user:`dhruvildarji`. diff --git a/aiohttp/web_response.py b/aiohttp/web_response.py index c88911c4dcc..2d5518c756c 100644 --- a/aiohttp/web_response.py +++ b/aiohttp/web_response.py @@ -612,6 +612,12 @@ def body(self, body: Any) -> None: self._body = None elif isinstance(body, (bytes, bytearray)): self._body = body + elif isinstance(body, str): + self._body = body.encode(self.charset or "utf-8") + if self.content_type == "application/octet-stream": + self.content_type = "text/plain" + if self.charset is None: + self.charset = "utf-8" else: try: self._body = body = payload.PAYLOAD_REGISTRY.get(body) diff --git a/tests/test_web_response.py b/tests/test_web_response.py index becbfedc965..6144865387e 100644 --- a/tests/test_web_response.py +++ b/tests/test_web_response.py @@ -1191,6 +1191,48 @@ def test_payload_body_get_text(payload: object, expected: str | None) -> None: assert resp.text == expected +def test_body_setter_with_str_stores_bytes() -> None: + """Setting body to a str should encode it to bytes (issue #2928).""" + resp = web.Response() + resp.body = "hello" + assert resp.body == b"hello" + assert isinstance(resp.body, bytes) + assert resp.text == "hello" + + +def test_body_setter_with_str_sets_content_type() -> None: + """Setting body to a str should set content_type to text/plain.""" + resp = web.Response() + resp.body = "hello" + assert resp.content_type == "text/plain" + assert resp.charset == "utf-8" + + +def test_body_setter_with_str_preserves_existing_content_type() -> None: + """Setting body to str should not override an existing non-default content_type.""" + resp = web.Response(content_type="text/html") + resp.body = "hello" + assert resp.content_type == "text/html" + + +def test_body_setter_with_str_uses_existing_charset() -> None: + """Setting body to str should use existing charset for encoding.""" + resp = web.Response(charset="latin-1", content_type="text/plain") + resp.body = "caf\u00e9" + assert resp.body == "caf\u00e9".encode("latin-1") + assert resp.text == "caf\u00e9" + + +def test_body_setter_str_then_text_roundtrip() -> None: + """body = str -> text -> body roundtrip should be consistent.""" + resp = web.Response() + resp.body = "test string" + text = resp.text + assert text == "test string" + resp.text = text + assert resp.body == b"test string" + + def test_response_set_content_length() -> None: resp = web.Response() with pytest.raises(RuntimeError):