# StreamedRequestBody<!-- -->

A request body sent from its source in chunks, so the body is never held in memory whole.

`HttpClient.call` and `HttpClientAsync.call` wrap a `data` argument that is a file-like object, an iterable of byte chunks, or a streamed `HttpResponse` in this class. The transport pulls the chunks from `iter_bytes` or `aiter_bytes` and sends each one as it arrives, and the body is never compressed. Build one yourself and pass it as the `data` to choose the `chunk_size`, and it is sent as it is.

An `io.IOBase` stream, such as an open file or an `io.BytesIO`, is read in `chunk_size` pieces. Any other object with a callable `read` is read whole with a single `read()` call and sent as one chunk, since nothing else about its shape is known.

The shared retry loop can send a body again only when its source is a seekable `io.IOBase` stream, in which case `rewind` seeks back to where the source was when the body was created. Any other source is consumed by the attempt that sends it, so the request gets a single attempt.

A file opened in text mode, or an iterable yielding strings, is UTF-8 encoded chunk by chunk. A file-like object whose `read` is a coroutine function, as `aiofiles` provides, and an async iterable can only be sent by the asynchronous client.

Warning

This is an experimental feature. The behavior and interface may change in future versions.

## Index[**](#Index)

### Async Resource Clients

* [**is_async](https://docs.apify.com/api/client/python/reference/class/StreamedRequestBody.md#is_async)

### Methods

* [**\_\_init\_\_](https://docs.apify.com/api/client/python/reference/class/StreamedRequestBody.md#__init__)
* [**aclose_chunks](https://docs.apify.com/api/client/python/reference/class/StreamedRequestBody.md#aclose_chunks)
* [**aiter_bytes](https://docs.apify.com/api/client/python/reference/class/StreamedRequestBody.md#aiter_bytes)
* [**close_chunks](https://docs.apify.com/api/client/python/reference/class/StreamedRequestBody.md#close_chunks)
* [**is_streamable](https://docs.apify.com/api/client/python/reference/class/StreamedRequestBody.md#is_streamable)
* [**iter_bytes](https://docs.apify.com/api/client/python/reference/class/StreamedRequestBody.md#iter_bytes)
* [**rewind](https://docs.apify.com/api/client/python/reference/class/StreamedRequestBody.md#rewind)

### Properties

* [**error](https://docs.apify.com/api/client/python/reference/class/StreamedRequestBody.md#error)
* [**rewindable](https://docs.apify.com/api/client/python/reference/class/StreamedRequestBody.md#rewindable)

## Async Resource Clients<!-- -->[**](<#Async Resource Clients>)

### [**](#is_async)is_async

**is_async: bool

Whether the chunks can only be produced asynchronously, so only `HttpClientAsync` can send the body.

## Methods<!-- -->[**](#Methods)

### [**](#__init__)\_\_init\_\_

* ****\_\_init\_\_**(source, \*, chunk_size): None

- Initialize the streamed request body.

  ***

  #### Parameters

  * ##### source: [StreamedBodySource](https://docs.apify.com/api/client/python/reference.md#StreamedBodySource)

    The object the chunks come from. See `is_streamable` for the accepted kinds.

  * ##### optionalkeyword-onlychunk_size: int = <!-- -->STREAMED_BODY_CHUNK_SIZE

    Size of the chunks an `io.IOBase` source is read in - bytes from a binary stream, characters from a text-mode one. Any other source decides its own chunk sizes.

  #### Returns None

### [**](#aclose_chunks)aclose_chunks

* **async **aclose_chunks**(): None

- Close the chunks the last `aiter_bytes` call handed out, and with them a generator or async generator source.

  The asynchronous counterpart of `close_chunks`.

  ***

  #### Returns None

### [**](#aiter_bytes)aiter_bytes

* ****aiter_bytes**(): AsyncGenerator\[bytes]

- Yield the body in chunks asynchronously, pulling a synchronous source in a worker thread.

  A blocking `read` or `__next__` would stall the event loop, so a synchronous file-like object or iterator is pulled through `asyncio.to_thread`, one chunk at a time. Closing the returned generator, directly or through `aclose_chunks`, also closes a generator or async generator source.

  ***

  #### Returns AsyncGenerator\[bytes]

### [**](#close_chunks)close_chunks

* ****close_chunks**(): None

- Close the chunks the last `iter_bytes` call handed out, and with them a generator source.

  The retry loop calls this once an attempt ends. A transport may stop pulling the chunks early, for example on an error response sent before the whole body arrived, and hold on to them for as long as its client lives, which keeps the source suspended. When the transport is still pulling a chunk in a worker thread, a generator source is closed and a file-like source is read no further as soon as that chunk arrives.

  ***

  #### Returns None

### [**](#is_streamable)is_streamable

* ****is_streamable**(value): TypeGuard\[[StreamedBodySource](https://docs.apify.com/api/client/python/reference.md#StreamedBodySource)]

- Return whether a request body can be streamed from a value.

  These are, checked in this order, a streamed `HttpResponse` (anything with a callable `iter_bytes`), an `io.IOBase` stream, any other file-like object (anything with a callable `read`), and an iterable or async iterable of byte chunks: an iterator such as a generator, or an object that only implements `__iter__` or `__aiter__`, which is what a class yielding chunks from a generator method looks like. A `str`, `bytes`, `bytearray`, a container such as a `list`, `tuple`, `set`, or `dict`, and a pydantic model are not sources, even though all of them can be iterated. They are the values the client uploads whole or serializes as JSON.

  A `StreamedRequestBody` matches on its own `iter_bytes`, which is how a hand-built body reaches the request pipeline untouched. The constructor refuses one, so a caller that builds a body from what this accepts has to check for an existing body first.

  ***

  #### Parameters

  * ##### value: object

  #### Returns TypeGuard\[[StreamedBodySource](https://docs.apify.com/api/client/python/reference.md#StreamedBodySource)]

### [**](#iter_bytes)iter_bytes

* ****iter_bytes**(): Generator\[bytes]

- Yield the body in chunks, reading an `io.IOBase` source in `chunk_size` pieces.

  Closing the returned generator, directly or through `close_chunks`, also closes a generator source.

  ***

  #### Returns Generator\[bytes]

### [**](#rewind)rewind

* ****rewind**(): None

- Seek the source back to where it was when the body was created, so the body can be sent again.

  ***

  #### Returns None

## Properties<!-- -->[**](#Properties)

### [**](#error)error

**error: Exception | None

The exception the source raised while the chunks were pulled, if any.

A transport reports such a failure as its own error, which may wrap the cause beyond recognition. The retry loop raises this exception instead, since sending the body again cannot fix its source.

### [**](#rewindable)rewindable

**rewindable: bool

Whether the body can be sent again after `rewind`, which only a seekable `io.IOBase` source allows.
