Async-first Python speed test library for measuring network throughput
Project description
pyasyncspeedtest
An async-first Python library for measuring network throughput via HTTP-based speed tests. Designed to be embedded into async applications, services, and workers.
Why This Exists
Most speedtest tools are designed as end-user CLI applications and rely on synchronous HTTP clients or threading. This makes them awkward to integrate into async Python applications (FastAPI services, async workers, aiohttp-based tools) without blocking the event loop or spawning threads.
pyasyncspeedtest provides a reusable async library that integrates cleanly with asyncio-based applications. It uses aiohttp for all network operations and follows async Python conventions.
Features
- Async server discovery and latency-based selection
- Concurrent download and upload speed measurement
- Geographic distance filtering using Haversine calculation
- Configurable test durations and server selection criteria
- Optional source address binding for multi-homed hosts
- Minimal dependencies (only
aiohttp) - No threads, no global state, no blocking I/O
Non-goals
This library measures application-level HTTP performance, not low-level network behavior. It does not:
- Perform kernel-level TCP benchmarking
- Measure raw socket throughput
- Replace
iperf,netperf, or similar tools - Claim to measure congestion control behavior or packet loss
- Provide CLI-first user experience (library-first design)
Results reflect HTTP transfer speeds as seen by an async Python application, including all protocol overhead.
Installation
pip install pyasyncspeedtest
Requires Python 3.10 or later.
Basic Usage
import asyncio
from pyasyncspeedtest import AsyncSpeedtest
async def main():
st = AsyncSpeedtest()
print("Finding best server...")
server = await st.get_best_server()
if server:
print(f"Server: {server['name']}, {server['country']}")
print("Testing download speed...")
await st.measure_download_speed()
print("Testing upload speed...")
await st.measure_upload_speed()
print(f"Download: {st.download * 8 / 1e6:.2f} Mbps")
print(f"Upload: {st.upload * 8 / 1e6:.2f} Mbps")
print(f"Ping: {st.ping:.1f} ms")
if __name__ == "__main__":
asyncio.run(main())
Advanced configuration:
st = AsyncSpeedtest(
source_address="192.168.1.100",
download_test_duration=20,
upload_test_duration=15,
max_server_distance=1000 # kilometers
)
API Stability
The public API is intentionally small:
AsyncSpeedtestclass and its public methodsrun_speedtest()convenience functionSpeedTestResult,SpeedTestConfig,ServerInfodataclassesSpeedTestErrorand subclasses for error handling
Internals (server list parsing, timing implementation, HTTP request details) are not stable and may change between minor releases. The library is pre-1.0 and the API may evolve based on usage feedback.
Error Handling
- Network failures (timeouts, DNS errors) are caught and logged; methods return gracefully
- Invalid usage (e.g., measuring speed before selecting a server) raises
RuntimeErrorwith clear messages - No silent failures; errors are either raised or logged at appropriate levels
- Empty server lists or malformed responses are handled defensively
Async & Performance Notes
- Uses
aiohttp.ClientSessionwith proper connection pooling - Explicit
ClientTimeoutobjects (no deprecated timeout APIs) - High-resolution timers (
time.perf_counter()) for accurate measurements - Bounded concurrency (configurable number of concurrent download streams)
- Safe for use in existing event loops (no
asyncio.run()internally) - Module-scoped logger; does not configure root logger
Testing
Unit tests use mocked network responses to validate parsing logic, distance calculations, and error handling:
pytest tests/
Tests do not make real network requests by default. Integration tests that contact actual Speedtest.net servers are excluded from the default test run.
License
MIT License. See LICENSE file for details.
Contributing
Contributions are welcome. Please:
- Keep changes small and focused
- Prioritize correctness and clarity over features
- Discuss significant API changes in an issue before opening a PR
- Ensure tests pass and add tests for new functionality
This library aims to remain simple and focused. Large feature additions may be declined if they add complexity without clear value for the async embedding use case.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file pyasyncspeedtest-0.1.0.tar.gz.
File metadata
- Download URL: pyasyncspeedtest-0.1.0.tar.gz
- Upload date:
- Size: 12.7 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
d43743058dc992ef6afcffb641501eb138530cd63644598c170c109af4afdb9b
|
|
| MD5 |
f98e54b86f2ee960d08de10cab9326ab
|
|
| BLAKE2b-256 |
05a7d39cd7499991eaa4a4800308eea39a943917d7b941ae0fcc6174a1de9225
|
File details
Details for the file pyasyncspeedtest-0.1.0-py3-none-any.whl.
File metadata
- Download URL: pyasyncspeedtest-0.1.0-py3-none-any.whl
- Upload date:
- Size: 10.6 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
1960fbc4a6b91e3c4c05f9dda57a3c554826b03bf6ab46927f265238a771d8b9
|
|
| MD5 |
feb00aaa6c7ef87b133d7753c5994024
|
|
| BLAKE2b-256 |
e4cddad8700ae219a2ea1235aa2d9199c9776b6e37823c9d403a76b3a0ce2b6b
|