Skip to main content

asyncly logo

Asyncly

PyPI version Python versions License Documentation

A tiny async HTTP client and a real aiohttp mock server for testing your integrations — built on aiohttp.

asyncly gives you two pieces that fit together:

  • BaseHttpClient — a thin, typed base class for HTTP clients with per-status response handlers, policy-driven retries, flexible timeouts, and first-class proxy support. InstrumentableHttpClient adds pluggable metrics (Prometheus / OpenTelemetry): requests, in-flight, network phases, and connection-pool stats.
  • srvmocker — spin up a real aiohttp test server (not a transport patch) to simulate upstreams and socket faults, assert what your client sent, and even route through a mock proxy.

📖 Read the full documentation →

Installation

pip install asyncly

Optional extras — msgspec, pydantic, orjson, prometheus, opentelemetry:

pip install "asyncly[pydantic]"

Quickstart

Define a client by subclassing BaseHttpClient and mapping status codes to handlers:

from http import HTTPStatus
from types import MappingProxyType

from aiohttp import ClientSession, hdrs
from pydantic import BaseModel

from asyncly import BaseHttpClient, DEFAULT_TIMEOUT, ResponseHandlersType
from asyncly.client.handlers.pydantic import parse_model
from asyncly.client.timeout import TimeoutType


class CatFact(BaseModel):
    fact: str
    length: int


class CatfactClient(BaseHttpClient):
    FACT_HANDLERS: ResponseHandlersType = MappingProxyType(
        {HTTPStatus.OK: parse_model(CatFact)}
    )

    async def fetch_fact(self, timeout: TimeoutType = DEFAULT_TIMEOUT) -> CatFact:
        return await self._make_req(
            method=hdrs.METH_GET,
            url=self._url / "fact",
            handlers=self.FACT_HANDLERS,
            timeout=timeout,
        )

Test it against a real mock server — no network, no monkeypatching:

from asyncly.srvmocker import JsonResponse, MockRoute, start_service


async def test_fetch_fact() -> None:
    routes = [MockRoute("GET", "/fact", "fact")]
    async with start_service(routes) as service:
        service.register("fact", JsonResponse({"fact": "Cats sleep a lot.", "length": 17}))

        async with ClientSession() as session:
            client = CatfactClient(url=service.url, session=session, client_name="catfact")
            fact = await client.fetch_fact()

        assert fact.fact == "Cats sleep a lot."
        service.assert_called("fact", times=1)

Prefer fixtures over boilerplate? asyncly ships a pytest plugin with mock_service and mock_proxy. See the Quickstart for more.

Why asyncly?

Unlike transport-patching mocks (aioresponses, respx), srvmocker runs a real aiohttp.TestServer inside your test loop — catching real sockets, timeouts, header auto-injection, and serialization quirks. See Testing strategies for the full comparison.

License

MIT

Metadata

Release files for asyncly 0.10.1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for asyncly 0.10.1
File Size Uploaded
asyncly-0.10.1.tar.gz 31.6 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for asyncly 0.10.1
File Interpreter ABI Platform
asyncly-0.10.1-py3-none-any.whl Python 3 none any Details

Total release size: 79.7 kB

Release files / asyncly-0.10.1.tar.gz

Download URL asyncly-0.10.1.tar.gz
Size 31.6 kB
Tags Source
SHA-256 checksum
How to use checksums
05e7b333ad0da693542fcde90644bd7345d7b91f47d5cf999d50e8e69ee1f1a9
BLAKE2b-256 checksum
How to use checksums
056c705c08ba48e3962f46da3aae9fb21fb155746d70bf5fffcbdaaf8774e8c0
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via uv/0.11.31 {"installer":{"name":"uv","version":"0.11.31","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

Release files / asyncly-0.10.1-py3-none-any.whl

Download URL asyncly-0.10.1-py3-none-any.whl
Size 48.0 kB
Tags Python 3
SHA-256 checksum
How to use checksums
1946c091201eccb7ec428f340ef1dd999a20326e13c443d960d92f487debd84b
BLAKE2b-256 checksum
How to use checksums
c2bc5fdf7b7be5e35ed83ec96d7f216b284746bc63d87d1228a99493b93ad42c
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via uv/0.11.31 {"installer":{"name":"uv","version":"0.11.31","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

Release history Release notifications | RSS feed

This release

0.10.1 This release

2 release files

0.10.0

2 release files

0.9.0

2 release files

0.8.0

2 release files

0.7.1

2 release files

0.7.0

2 release files

0.6.2

2 release files

0.6.1

2 release files

0.6.0

2 release files

0.5.1

2 release files

0.5.0

2 release files

0.4.1

2 release files

0.3.4

2 release files

0.3.3

2 release files

0.3.2

2 release files

0.3.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page