diff --git a/src/ahttpx/__init__.py b/src/ahttpx/__init__.py index da69026..2d181f0 100644 --- a/src/ahttpx/__init__.py +++ b/src/ahttpx/__init__.py @@ -1,7 +1,7 @@ from .__version__ import __title__, __version__ from ._client import * # Client from ._connection import * # Connection, Transport -from ._content import * # Content, File, Files, Form, HTML, JSON, MultiPart, Text +from ._content import * # Binary, Content, File, Files, Form, HTML, JSON, MultiPart, Text from ._headers import * # Headers from ._network import * # NetworkBackend, NetworkStream, timeout from ._parsers import * # HTTPParser, HTTPStream, ProtocolError @@ -18,6 +18,7 @@ __all__ = [ "__title__", "__version__", + "Binary", "ByteStream", "Client", "Connection", diff --git a/src/ahttpx/_content.py b/src/ahttpx/_content.py index ee7e0be..ae849b4 100644 --- a/src/ahttpx/_content.py +++ b/src/ahttpx/_content.py @@ -6,6 +6,7 @@ from ._urlencode import urldecode, urlencode __all__ = [ + "Binary", "Content", "Form", "File", @@ -36,6 +37,9 @@ def open(self) -> Stream: def content_type(self) -> str: raise NotImplementedError() + def __bytes__(self): + raise TypeError(f"Content {self.__class__.__name__} does not support a bytes interface.") + class Form(typing.Mapping[str, str], Content): """ @@ -73,12 +77,12 @@ def __init__( d.setdefault(k, []).append(v) self._dict = d + self._content = str(self).encode("ascii") # Content API def open(self) -> Stream: - content = str(self).encode("ascii") - return ByteStream(content) + return ByteStream(self._content) def content_type(self) -> str: return "application/x-www-form-urlencoded" @@ -289,19 +293,22 @@ def __repr__(self) -> str: class JSON(Content): def __init__(self, data: typing.Any) -> None: self._data = data - - def open(self) -> Stream: - content = json.dumps( + self._content = json.dumps( self._data, ensure_ascii=False, separators=(",", ":"), allow_nan=False ).encode("utf-8") - return ByteStream(content) + + def open(self) -> Stream: + return ByteStream(self._content) def content_type(self) -> str: return "application/json" + def __bytes__(self) -> bytes: + return self._content + def __repr__(self) -> str: return f"" @@ -309,14 +316,17 @@ def __repr__(self) -> str: class Text(Content): def __init__(self, text: str) -> None: self._text = text + self._content = self._text.encode("utf-8") def open(self) -> Stream: - content = self._text.encode("utf-8") - return ByteStream(content) + return ByteStream(self._content) def content_type(self) -> str: return "text/plain; charset='utf-8'" + def __bytes__(self) -> bytes: + return self._content + def __repr__(self) -> str: return f"" @@ -324,18 +334,39 @@ def __repr__(self) -> str: class HTML(Content): def __init__(self, text: str) -> None: self._text = text + self._content = self._text.encode("utf-8") def open(self) -> Stream: - content = self._text.encode("utf-8") - return ByteStream(content) + return ByteStream(self._content) def content_type(self) -> str: return "text/html; charset='utf-8'" + def __bytes__(self) -> bytes: + return self._content + def __repr__(self) -> str: return f"" +class Binary(Content): + def __init__(self, content: bytes, content_type: str) -> None: + self._content = content + self._content_type = content_type + + def open(self) -> Stream: + return ByteStream(self._content) + + def content_type(self) -> str: + return self._content_type + + def __bytes__(self) -> bytes: + return self._content + + def __repr__(self) -> str: + return f"" + + class MultiPart(Content): def __init__( self, diff --git a/src/httpx/__init__.py b/src/httpx/__init__.py index da69026..2d181f0 100644 --- a/src/httpx/__init__.py +++ b/src/httpx/__init__.py @@ -1,7 +1,7 @@ from .__version__ import __title__, __version__ from ._client import * # Client from ._connection import * # Connection, Transport -from ._content import * # Content, File, Files, Form, HTML, JSON, MultiPart, Text +from ._content import * # Binary, Content, File, Files, Form, HTML, JSON, MultiPart, Text from ._headers import * # Headers from ._network import * # NetworkBackend, NetworkStream, timeout from ._parsers import * # HTTPParser, HTTPStream, ProtocolError @@ -18,6 +18,7 @@ __all__ = [ "__title__", "__version__", + "Binary", "ByteStream", "Client", "Connection", diff --git a/src/httpx/_content.py b/src/httpx/_content.py index ee7e0be..ae849b4 100644 --- a/src/httpx/_content.py +++ b/src/httpx/_content.py @@ -6,6 +6,7 @@ from ._urlencode import urldecode, urlencode __all__ = [ + "Binary", "Content", "Form", "File", @@ -36,6 +37,9 @@ def open(self) -> Stream: def content_type(self) -> str: raise NotImplementedError() + def __bytes__(self): + raise TypeError(f"Content {self.__class__.__name__} does not support a bytes interface.") + class Form(typing.Mapping[str, str], Content): """ @@ -73,12 +77,12 @@ def __init__( d.setdefault(k, []).append(v) self._dict = d + self._content = str(self).encode("ascii") # Content API def open(self) -> Stream: - content = str(self).encode("ascii") - return ByteStream(content) + return ByteStream(self._content) def content_type(self) -> str: return "application/x-www-form-urlencoded" @@ -289,19 +293,22 @@ def __repr__(self) -> str: class JSON(Content): def __init__(self, data: typing.Any) -> None: self._data = data - - def open(self) -> Stream: - content = json.dumps( + self._content = json.dumps( self._data, ensure_ascii=False, separators=(",", ":"), allow_nan=False ).encode("utf-8") - return ByteStream(content) + + def open(self) -> Stream: + return ByteStream(self._content) def content_type(self) -> str: return "application/json" + def __bytes__(self) -> bytes: + return self._content + def __repr__(self) -> str: return f"" @@ -309,14 +316,17 @@ def __repr__(self) -> str: class Text(Content): def __init__(self, text: str) -> None: self._text = text + self._content = self._text.encode("utf-8") def open(self) -> Stream: - content = self._text.encode("utf-8") - return ByteStream(content) + return ByteStream(self._content) def content_type(self) -> str: return "text/plain; charset='utf-8'" + def __bytes__(self) -> bytes: + return self._content + def __repr__(self) -> str: return f"" @@ -324,18 +334,39 @@ def __repr__(self) -> str: class HTML(Content): def __init__(self, text: str) -> None: self._text = text + self._content = self._text.encode("utf-8") def open(self) -> Stream: - content = self._text.encode("utf-8") - return ByteStream(content) + return ByteStream(self._content) def content_type(self) -> str: return "text/html; charset='utf-8'" + def __bytes__(self) -> bytes: + return self._content + def __repr__(self) -> str: return f"" +class Binary(Content): + def __init__(self, content: bytes, content_type: str) -> None: + self._content = content + self._content_type = content_type + + def open(self) -> Stream: + return ByteStream(self._content) + + def content_type(self) -> str: + return self._content_type + + def __bytes__(self) -> bytes: + return self._content + + def __repr__(self) -> str: + return f"" + + class MultiPart(Content): def __init__( self, diff --git a/tests/test_ahttpx/test_content.py b/tests/test_ahttpx/test_content.py index f2f6dcb..a98ddde 100644 --- a/tests/test_ahttpx/test_content.py +++ b/tests/test_ahttpx/test_content.py @@ -15,6 +15,7 @@ async def test_html(): assert await stream.read() == b'Hello, world' assert content_type == "text/html; charset='utf-8'" + assert bytes(html) == b'Hello, world' # Text @@ -28,6 +29,7 @@ async def test_text(): assert await stream.read() == b'Hello, world' assert content_type == "text/plain; charset='utf-8'" + assert bytes(text) == b'Hello, world' # JSON @@ -41,6 +43,7 @@ async def test_json(): assert await stream.read() == b'{"data":123}' assert content_type == "application/json" + assert bytes(data) == b'{"data":123}' # Form diff --git a/tests/test_httpx/test_content.py b/tests/test_httpx/test_content.py index bc740ce..1e883f3 100644 --- a/tests/test_httpx/test_content.py +++ b/tests/test_httpx/test_content.py @@ -14,6 +14,7 @@ def test_html(): assert stream.read() == b'Hello, world' assert content_type == "text/html; charset='utf-8'" + assert bytes(html) == b'Hello, world' # Text @@ -26,6 +27,7 @@ def test_text(): assert stream.read() == b'Hello, world' assert content_type == "text/plain; charset='utf-8'" + assert bytes(text) == b'Hello, world' # JSON @@ -38,6 +40,7 @@ def test_json(): assert stream.read() == b'{"data":123}' assert content_type == "application/json" + assert bytes(data) == b'{"data":123}' # Form