# AsyncCurlMulti Object

Note

The `AsyncCurlMulti` API is experimental and may change in a future release.

class pycurl.AsyncCurlMulti(close_handles=False) → AsyncCurlMulti object

  An asyncio-driven wrapper around `pycurl.CurlMulti`. Each `pycurl.Curl` transfer is represented by an `asyncio.Future` that resolves to the same `Curl` object on success or raises `pycurl.error` on failure.

  The constructor does not require a running event loop; the loop is captured on the first call to `add_handle()` and the instance is bound to that loop for its lifetime.

  A selector-style asyncio event loop is required. On a non-selector loop (e.g., Windows `ProactorEventLoop`) `add_handle()` raises `RuntimeError` with guidance on switching policy.

  Always call `aclose()` (or use `async with`) to release the underlying multi handle promptly.

  close_handles is forwarded to `pycurl.CurlMulti`. When `True`, any easy handle still attached to the multi when `aclose()` runs is also closed by libcurl.

  Example:

      async with pycurl.AsyncCurlMulti() as multi:
          curl = pycurl.Curl()
          curl.setopt(pycurl.URL, "https://example.com")
          await multi.perform(curl)
          print(curl.getinfo(pycurl.RESPONSE_CODE))

  Batch example:

      async with pycurl.AsyncCurlMulti() as multi:
          for url in urls:
              curl = pycurl.Curl()
              curl.setopt(pycurl.URL, url)
              multi.add_handle(curl)
          results = await asyncio.gather(*multi.futures())

  AsyncCurlMulti objects have the following methods:

  __init__(close_handles: bool = False) → None
  setopt(option, value) → None

    Sets a multi-handle option. Equivalent to `pycurl.CurlMulti.setopt()`, except that `M_SOCKETFUNCTION`, `M_TIMERFUNCTION`, and (on libcurl 8.17.0+) `M_NOTIFYFUNCTION` are owned by `AsyncCurlMulti` and raise `ValueError` if set externally.

    option is a `pycurl.M_*` constant identifying which option to set. value is the new option value; different options accept values of different types (see `pycurl.CurlMulti.setopt()`).

  add_handle(curl) → asyncio.Future

    Schedules curl for transfer and returns an `asyncio.Future` that resolves to curl on success or raises `pycurl.error` on failure. Cancelling the future removes the handle; cleanup runs on the next event-loop tick.

    curl is a `pycurl.Curl` easy handle.

    The first call captures the running event loop and binds this instance to it. Raises `RuntimeError` if called outside a running loop, after `aclose()`, or if curl is already registered.

  remove_handle(curl) → None

    Removes curl from this multi handle and cancels its future (if not already done). Synchronous; if you need to observe the cancellation propagate, await the future returned from the original `add_handle()` call.

    curl is a `pycurl.Curl` easy handle. Raises `RuntimeError` if curl is not registered or after `aclose()`. Raises `pycurl.error` if libcurl rejects the removal.

  async perform(curl) → Curl object

    Coroutine equivalent to `await self.add_handle(curl)`. Schedules curl for transfer and returns it once the transfer completes. Raises `pycurl.error` on failure.

    curl is a `pycurl.Curl` easy handle.

  futures(curls=None) → tuple of asyncio.Future

    Returns a snapshot of futures for transfers currently registered with this multi handle.

    curls is either `None` (the default) or an iterable of `pycurl.Curl` easy handles. When `None`, the result contains every pending future in the order in which the handles were added via `add_handle()`. When an iterable is given, the result contains the corresponding futures in input order and length (so duplicates yield duplicate references to the same future).

    Completed or cancelled transfers are not included in later snapshots.

    Raises `KeyError` if any handle in curls is not currently registered.

  async aclose() → None

    Coroutine. Cancels the pending timer, removes all in-flight handles, unregisters socket watchers, and closes the underlying multi handle. Pending futures are cancelled. Idempotent.

  closed

    Whether the underlying `pycurl.CurlMulti` handle is closed.

  async __aenter__() → AsyncCurlMulti
  async __aexit__(exc_type: type[BaseException] | None, exc: BaseException | None, tb: Any) → None