Skip to content

Conversation

@rodrigobnogueira
Copy link

@rodrigobnogueira rodrigobnogueira commented Jan 17, 2026

What do these changes do?

Adds a new example (examples/rate_limit_middleware.py) demonstrating rate limiting middleware for the aiohttp client using the token bucket algorithm.

Features:

  • Configurable rate and burst size
  • Per-domain rate limiting
  • Automatic Retry-After header handling
  • Self-contained test server for demonstration

Are there changes in behavior for the user?

No. This is a new example file only — no changes to the aiohttp library code.

Is it a substantial burden for the maintainers to support this?

No. This is a standalone example file demonstrating existing middleware functionality. It uses stable public APIs and doesn't add new library code. Maintenance burden is minimal.

Related issue number

N/A — New example contribution.

Checklist

  • I think the code is well written
  • Unit tests for the changes exist
  • Documentation reflects the changes
  • If you provide code modification, please add yourself to CONTRIBUTORS.txt
  • Add a new news fragment into the CHANGES/ folder

This example demonstrates how to implement client-side rate limiting
using the token bucket algorithm with support for:

- Configurable rate and burst size
- Per-domain rate limiting for multi-host scenarios
- Automatic Retry-After header handling

Includes a self-contained test server for demonstration.
@psf-chronographer psf-chronographer bot added the bot:chronographer:provided There is a change note present in this PR label Jan 17, 2026
@codspeed-hq
Copy link

codspeed-hq bot commented Jan 17, 2026

Merging this PR will not alter performance

✅ 59 untouched benchmarks


Comparing rodrigobnogueira:add-rate-limit-middleware-example (9f7a307) with master (e6c565a)

Open in CodSpeed

@codecov
Copy link

codecov bot commented Jan 17, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 98.75%. Comparing base (e6c565a) to head (9f7a307).
✅ All tests successful. No failed tests found.

Additional details and impacted files
@@           Coverage Diff           @@
##           master   #11969   +/-   ##
=======================================
  Coverage   98.75%   98.75%           
=======================================
  Files         127      127           
  Lines       44655    44655           
  Branches     2367     2367           
=======================================
  Hits        44101    44101           
  Misses        393      393           
  Partials      161      161           
Flag Coverage Δ
CI-GHA 98.61% <ø> (ø)
OS-Linux 98.35% <ø> (ø)
OS-Windows 96.70% <ø> (-0.01%) ⬇️
OS-macOS 97.58% <ø> (-0.01%) ⬇️
Py-3.10.11 97.13% <ø> (-0.01%) ⬇️
Py-3.10.19 97.62% <ø> (ø)
Py-3.11.14 97.82% <ø> (ø)
Py-3.11.9 97.34% <ø> (ø)
Py-3.12.10 97.44% <ø> (-0.01%) ⬇️
Py-3.12.12 97.93% <ø> (ø)
Py-3.13.11 98.17% <ø> (+<0.01%) ⬆️
Py-3.14.2 98.15% <ø> (-0.01%) ⬇️
Py-3.14.2t 97.24% <ø> (+<0.01%) ⬆️
Py-pypy3.11.13-7.3.20 97.38% <ø> (-0.01%) ⬇️
VM-macos 97.58% <ø> (-0.01%) ⬇️
VM-ubuntu 98.35% <ø> (ø)
VM-windows 96.70% <ø> (-0.01%) ⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

@webknjaz webknjaz requested review from Dreamsorcerer and removed request for asvetlov January 21, 2026 13:51
@webknjaz
Copy link
Member

@Dreamsorcerer do we have any guidance on the examples folder? Some of those files are decade-old and I, for example, never really look in there.

@rodrigobnogueira would you be interested in trying to get pytest to run the examples and getting code coverage as acceptance tests?

@rodrigobnogueira
Copy link
Author

rodrigobnogueira commented Jan 21, 2026

@Dreamsorcerer do we have any guidance on the examples folder? Some of those files are decade-old and I, for example, never really look in there.

@rodrigobnogueira would you be interested in trying to get pytest to run the examples and getting code coverage as acceptance tests?

Yes @webknjaz , I can try that to get pytest to run the examples, but I suppose the examples guidance should be the first step, because some examples may not comply.


Guidance draft:

  • No external dependencies: Examples should not rely on dependencies outside the repository or special local configurations unless clearly stated.

Potential tweaks of the rule above: if an example must use an external dep (e.g., for integrating with a database like asyncpg in a real-world demo), it should include a clear setup section at the top, like a requirements.txt snippet or install command.

  • Imports: Examples should not contain relative imports (e.g., from .. import aiohttp).
  • Minimal but complete: They should demonstrate one concept clearly without excessive boilerplate, but include enough code to actually run.
  • User input: The example should not require user input for the test to run.
  • Documentation: Each example should include a docstring explaining what it demonstrates and how to run it.

@rodrigobnogueira
Copy link
Author

rodrigobnogueira commented Jan 21, 2026

Here is a comprehensive examples scenario with the help of Gemini.

Proposal for Guidance for Examples after the Detailed Status section. I think we can change the existing examples to comply to the proposal. I could try that, but I think I need a strategy from you guys. Do I need to open a issue? Can I submit one PR for each adjusted example?

Status Report on Examples

This report summarizes the execution status of all example scripts in the examples/ directory.

Summary

Total Examples Passed Failed Interactive
24 16 6 2

Note: Files that serve as helpers (e.g., fake_server.py) or data were excluded from the primary count but tested for importability.

Detailed Status

Example File Status Issue / Notes Suggested Solution
background_tasks.py Failed ModuleNotFoundError: No module named 'valkey' Switch to in-memory dict or aiocache.
basic_auth_middleware.py Passed - -
cli_app.py ⚠️ Interactive Requires CLI args (no output on default run). Add default args or print help if none provided.
client_auth.py Failed RuntimeError: There is no current event loop Use asyncio.run() instead of get_event_loop().
client_json.py Failed RuntimeError: There is no current event loop Use asyncio.run() instead of get_event_loop().
client_ws.py ⚠️ Interactive Blocked on input("Please enter your name: "). Add CLI arg for name; fallback to default if non-interactive.
combined_middleware.py Passed - -
curl.py Failed RuntimeError: There is no current event loop Use asyncio.run() instead of get_event_loop().
digest_auth_qop_auth.py Passed - -
fake_server.py Failed RuntimeError: There is no current event loop Use asyncio.run() (helper script, but runnable).
logging_middleware.py Passed - -
lowlevel_srv.py Failed RuntimeError: There is no current event loop Use asyncio.run() instead of get_event_loop().
rate_limit_middleware.py Passed Self-validating. -
retry_middleware.py Passed (Server) Started successfully. -
server_simple.py Passed (Server) Started successfully. -
static_files.py Passed (Server) Started successfully. -
token_refresh_middleware.py Passed - -
web_classview.py Passed (Server) Started successfully. -
web_cookies.py Passed (Server) Started successfully. -
web_rewrite_headers_middleware.py Passed (Server) Started successfully. -
web_srv.py Passed (Server) Started successfully. -
web_srv_route_deco.py Passed (Server) Started successfully. -
web_srv_route_table.py Passed (Server) Started successfully. -
web_ws.py Passed (Server) Started successfully. -

Guidance for Examples

To ensure the examples/ directory remains high-quality, validatable, and easy for users to learn from, we propose the following guidelines for all current and future examples:

1. Zero External Dependencies

Examples should run using only aiohttp and the Python standard library.

  • Why: Ideally, users should be able to copy an example code into their own project, install aiohttp, and run the example.
  • Requirement: Do not import redis, sqlalchemy, or other third-party libraries unless the example is specifically about integrating with them (in which case, provide a clear fallback or mock).

2. CI-Ready & Non-Interactive

Examples must be fully runnable from start to finish without blocking on user input.

  • Why: This allows us to "smoke test" examples in CI to prevent them from breaking silently (prevention of "bit rot").
  • Requirement: Avoid input(). Use command-line arguments (via sys.argv or argparse) or hardcoded defaults if arguments are missing.

3. Modern Asyncio Standards

Examples must use modern, recommended asyncio patterns compatible with the latest supported Python versions.

  • Why: Examples are often copied by users as a collection of "best practices." We should not propagate legacy or deprecated patterns.
  • Requirement: Use asyncio.run(main()) for entry points. Avoid manual event loop management (get_event_loop()) unless absolutely necessary for low-level demonstrations.

4. Self-Documentation & Validation

Each example should be self-explanatory and, ideally, self-validating.

  • Why: Users learn by reading and running.
  • Requirement:
    • Include a module-level docstring describing what the example demonstrates.
    • (Optional but Recommended) Include a simple assertion or print statement indicating success, so a user knows it worked (e.g., printing "Success: Got 200 OK").

@Dreamsorcerer
Copy link
Member

@Dreamsorcerer do we have any guidance on the examples folder? Some of those files are decade-old and I, for example, never really look in there.

Not particularly. This PR is still open on my computer to review, will get back to it soon enough.

@rodrigobnogueira would you be interested in trying to get pytest to run the examples and getting code coverage as acceptance tests?

I guess the question is whether all examples should be cluttered with tests? We have mypy running on them which atleast avoids regular API breakage like we often had in the past.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bot:chronographer:provided There is a change note present in this PR

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants