99import inspect
1010import logging
1111import platform
12+ import warnings
1213import email.utils
1314from types import TracebackType
1415from random import random
5152 ResponseT,
5253 AnyMapping,
5354 PostParser,
55+ BinaryTypes,
5456 RequestFiles,
5557 HttpxSendArgs,
5658 RequestOptions,
59+ AsyncBinaryTypes,
5760 HttpxRequestFiles,
5861 ModelBuilderProtocol,
5962 not_given,
@@ -477,8 +480,19 @@ def _build_request(
477480 retries_taken: int = 0,
478481 ) -> httpx.Request:
479482 if log.isEnabledFor(logging.DEBUG):
480- log.debug("Request options: %s", model_dump(options, exclude_unset=True))
481-
483+ log.debug(
484+ "Request options: %s",
485+ model_dump(
486+ options,
487+ exclude_unset=True,
488+ # Pydantic v1 can't dump every type we support in content, so we exclude it for now.
489+ exclude={
490+ "content",
491+ }
492+ if PYDANTIC_V1
493+ else {},
494+ ),
495+ )
482496 kwargs: dict[str, Any] = {}
483497
484498 json_data = options.json_data
@@ -532,7 +546,13 @@ def _build_request(
532546 is_body_allowed = options.method.lower() != "get"
533547
534548 if is_body_allowed:
535- if isinstance(json_data, bytes):
549+ if options.content is not None and json_data is not None:
550+ raise TypeError("Passing both `content` and `json_data` is not supported")
551+ if options.content is not None and files is not None:
552+ raise TypeError("Passing both `content` and `files` is not supported")
553+ if options.content is not None:
554+ kwargs["content"] = options.content
555+ elif isinstance(json_data, bytes):
536556 kwargs["content"] = json_data
537557 else:
538558 kwargs["json"] = json_data if is_given(json_data) else None
@@ -1194,6 +1214,7 @@ def post(
11941214 *,
11951215 cast_to: Type[ResponseT],
11961216 body: Body | None = None,
1217+ content: BinaryTypes | None = None,
11971218 options: RequestOptions = {},
11981219 files: RequestFiles | None = None,
11991220 stream: Literal[False] = False,
@@ -1206,6 +1227,7 @@ def post(
12061227 *,
12071228 cast_to: Type[ResponseT],
12081229 body: Body | None = None,
1230+ content: BinaryTypes | None = None,
12091231 options: RequestOptions = {},
12101232 files: RequestFiles | None = None,
12111233 stream: Literal[True],
@@ -1219,6 +1241,7 @@ def post(
12191241 *,
12201242 cast_to: Type[ResponseT],
12211243 body: Body | None = None,
1244+ content: BinaryTypes | None = None,
12221245 options: RequestOptions = {},
12231246 files: RequestFiles | None = None,
12241247 stream: bool,
@@ -1231,13 +1254,25 @@ def post(
12311254 *,
12321255 cast_to: Type[ResponseT],
12331256 body: Body | None = None,
1257+ content: BinaryTypes | None = None,
12341258 options: RequestOptions = {},
12351259 files: RequestFiles | None = None,
12361260 stream: bool = False,
12371261 stream_cls: type[_StreamT] | None = None,
12381262 ) -> ResponseT | _StreamT:
1263+ if body is not None and content is not None:
1264+ raise TypeError("Passing both `body` and `content` is not supported")
1265+ if files is not None and content is not None:
1266+ raise TypeError("Passing both `files` and `content` is not supported")
1267+ if isinstance(body, bytes):
1268+ warnings.warn(
1269+ "Passing raw bytes as `body` is deprecated and will be removed in a future version. "
1270+ "Please pass raw bytes via the `content` parameter instead.",
1271+ DeprecationWarning,
1272+ stacklevel=2,
1273+ )
12391274 opts = FinalRequestOptions.construct(
1240- method="post", url=path, json_data=body, files=to_httpx_files(files), **options
1275+ method="post", url=path, json_data=body, content=content, files=to_httpx_files(files), **options
12411276 )
12421277 return cast(ResponseT, self.request(cast_to, opts, stream=stream, stream_cls=stream_cls))
12431278
@@ -1247,11 +1282,23 @@ def patch(
12471282 *,
12481283 cast_to: Type[ResponseT],
12491284 body: Body | None = None,
1285+ content: BinaryTypes | None = None,
12501286 files: RequestFiles | None = None,
12511287 options: RequestOptions = {},
12521288 ) -> ResponseT:
1289+ if body is not None and content is not None:
1290+ raise TypeError("Passing both `body` and `content` is not supported")
1291+ if files is not None and content is not None:
1292+ raise TypeError("Passing both `files` and `content` is not supported")
1293+ if isinstance(body, bytes):
1294+ warnings.warn(
1295+ "Passing raw bytes as `body` is deprecated and will be removed in a future version. "
1296+ "Please pass raw bytes via the `content` parameter instead.",
1297+ DeprecationWarning,
1298+ stacklevel=2,
1299+ )
12531300 opts = FinalRequestOptions.construct(
1254- method="patch", url=path, json_data=body, files=to_httpx_files(files), **options
1301+ method="patch", url=path, json_data=body, content=content, files=to_httpx_files(files), **options
12551302 )
12561303 return self.request(cast_to, opts)
12571304
@@ -1261,11 +1308,23 @@ def put(
12611308 *,
12621309 cast_to: Type[ResponseT],
12631310 body: Body | None = None,
1311+ content: BinaryTypes | None = None,
12641312 files: RequestFiles | None = None,
12651313 options: RequestOptions = {},
12661314 ) -> ResponseT:
1315+ if body is not None and content is not None:
1316+ raise TypeError("Passing both `body` and `content` is not supported")
1317+ if files is not None and content is not None:
1318+ raise TypeError("Passing both `files` and `content` is not supported")
1319+ if isinstance(body, bytes):
1320+ warnings.warn(
1321+ "Passing raw bytes as `body` is deprecated and will be removed in a future version. "
1322+ "Please pass raw bytes via the `content` parameter instead.",
1323+ DeprecationWarning,
1324+ stacklevel=2,
1325+ )
12671326 opts = FinalRequestOptions.construct(
1268- method="put", url=path, json_data=body, files=to_httpx_files(files), **options
1327+ method="put", url=path, json_data=body, content=content, files=to_httpx_files(files), **options
12691328 )
12701329 return self.request(cast_to, opts)
12711330
@@ -1275,9 +1334,19 @@ def delete(
12751334 *,
12761335 cast_to: Type[ResponseT],
12771336 body: Body | None = None,
1337+ content: BinaryTypes | None = None,
12781338 options: RequestOptions = {},
12791339 ) -> ResponseT:
1280- opts = FinalRequestOptions.construct(method="delete", url=path, json_data=body, **options)
1340+ if body is not None and content is not None:
1341+ raise TypeError("Passing both `body` and `content` is not supported")
1342+ if isinstance(body, bytes):
1343+ warnings.warn(
1344+ "Passing raw bytes as `body` is deprecated and will be removed in a future version. "
1345+ "Please pass raw bytes via the `content` parameter instead.",
1346+ DeprecationWarning,
1347+ stacklevel=2,
1348+ )
1349+ opts = FinalRequestOptions.construct(method="delete", url=path, json_data=body, content=content, **options)
12811350 return self.request(cast_to, opts)
12821351
12831352 def get_api_list(
@@ -1717,6 +1786,7 @@ async def post(
17171786 *,
17181787 cast_to: Type[ResponseT],
17191788 body: Body | None = None,
1789+ content: AsyncBinaryTypes | None = None,
17201790 files: RequestFiles | None = None,
17211791 options: RequestOptions = {},
17221792 stream: Literal[False] = False,
@@ -1729,6 +1799,7 @@ async def post(
17291799 *,
17301800 cast_to: Type[ResponseT],
17311801 body: Body | None = None,
1802+ content: AsyncBinaryTypes | None = None,
17321803 files: RequestFiles | None = None,
17331804 options: RequestOptions = {},
17341805 stream: Literal[True],
@@ -1742,6 +1813,7 @@ async def post(
17421813 *,
17431814 cast_to: Type[ResponseT],
17441815 body: Body | None = None,
1816+ content: AsyncBinaryTypes | None = None,
17451817 files: RequestFiles | None = None,
17461818 options: RequestOptions = {},
17471819 stream: bool,
@@ -1754,13 +1826,25 @@ async def post(
17541826 *,
17551827 cast_to: Type[ResponseT],
17561828 body: Body | None = None,
1829+ content: AsyncBinaryTypes | None = None,
17571830 files: RequestFiles | None = None,
17581831 options: RequestOptions = {},
17591832 stream: bool = False,
17601833 stream_cls: type[_AsyncStreamT] | None = None,
17611834 ) -> ResponseT | _AsyncStreamT:
1835+ if body is not None and content is not None:
1836+ raise TypeError("Passing both `body` and `content` is not supported")
1837+ if files is not None and content is not None:
1838+ raise TypeError("Passing both `files` and `content` is not supported")
1839+ if isinstance(body, bytes):
1840+ warnings.warn(
1841+ "Passing raw bytes as `body` is deprecated and will be removed in a future version. "
1842+ "Please pass raw bytes via the `content` parameter instead.",
1843+ DeprecationWarning,
1844+ stacklevel=2,
1845+ )
17621846 opts = FinalRequestOptions.construct(
1763- method="post", url=path, json_data=body, files=await async_to_httpx_files(files), **options
1847+ method="post", url=path, json_data=body, content=content, files=await async_to_httpx_files(files), **options
17641848 )
17651849 return await self.request(cast_to, opts, stream=stream, stream_cls=stream_cls)
17661850
@@ -1770,11 +1854,28 @@ async def patch(
17701854 *,
17711855 cast_to: Type[ResponseT],
17721856 body: Body | None = None,
1857+ content: AsyncBinaryTypes | None = None,
17731858 files: RequestFiles | None = None,
17741859 options: RequestOptions = {},
17751860 ) -> ResponseT:
1861+ if body is not None and content is not None:
1862+ raise TypeError("Passing both `body` and `content` is not supported")
1863+ if files is not None and content is not None:
1864+ raise TypeError("Passing both `files` and `content` is not supported")
1865+ if isinstance(body, bytes):
1866+ warnings.warn(
1867+ "Passing raw bytes as `body` is deprecated and will be removed in a future version. "
1868+ "Please pass raw bytes via the `content` parameter instead.",
1869+ DeprecationWarning,
1870+ stacklevel=2,
1871+ )
17761872 opts = FinalRequestOptions.construct(
1777- method="patch", url=path, json_data=body, files=await async_to_httpx_files(files), **options
1873+ method="patch",
1874+ url=path,
1875+ json_data=body,
1876+ content=content,
1877+ files=await async_to_httpx_files(files),
1878+ **options,
17781879 )
17791880 return await self.request(cast_to, opts)
17801881
@@ -1784,11 +1885,23 @@ async def put(
17841885 *,
17851886 cast_to: Type[ResponseT],
17861887 body: Body | None = None,
1888+ content: AsyncBinaryTypes | None = None,
17871889 files: RequestFiles | None = None,
17881890 options: RequestOptions = {},
17891891 ) -> ResponseT:
1892+ if body is not None and content is not None:
1893+ raise TypeError("Passing both `body` and `content` is not supported")
1894+ if files is not None and content is not None:
1895+ raise TypeError("Passing both `files` and `content` is not supported")
1896+ if isinstance(body, bytes):
1897+ warnings.warn(
1898+ "Passing raw bytes as `body` is deprecated and will be removed in a future version. "
1899+ "Please pass raw bytes via the `content` parameter instead.",
1900+ DeprecationWarning,
1901+ stacklevel=2,
1902+ )
17901903 opts = FinalRequestOptions.construct(
1791- method="put", url=path, json_data=body, files=await async_to_httpx_files(files), **options
1904+ method="put", url=path, json_data=body, content=content, files=await async_to_httpx_files(files), **options
17921905 )
17931906 return await self.request(cast_to, opts)
17941907
@@ -1798,9 +1911,19 @@ async def delete(
17981911 *,
17991912 cast_to: Type[ResponseT],
18001913 body: Body | None = None,
1914+ content: AsyncBinaryTypes | None = None,
18011915 options: RequestOptions = {},
18021916 ) -> ResponseT:
1803- opts = FinalRequestOptions.construct(method="delete", url=path, json_data=body, **options)
1917+ if body is not None and content is not None:
1918+ raise TypeError("Passing both `body` and `content` is not supported")
1919+ if isinstance(body, bytes):
1920+ warnings.warn(
1921+ "Passing raw bytes as `body` is deprecated and will be removed in a future version. "
1922+ "Please pass raw bytes via the `content` parameter instead.",
1923+ DeprecationWarning,
1924+ stacklevel=2,
1925+ )
1926+ opts = FinalRequestOptions.construct(method="delete", url=path, json_data=body, content=content, **options)
18041927 return await self.request(cast_to, opts)
18051928
18061929 def get_api_list(
0 commit comments