From 54db3b4cbc6a3a1690a5010409b7077605649521 Mon Sep 17 00:00:00 2001 From: Artur Shiriev Date: Thu, 2 Jul 2026 13:02:30 +0300 Subject: [PATCH 1/3] docs: design for modern-di-aiohttp brand mark Graphic-only: async event-loop-in-disc mark (candidate A), assets generated in .github. Public surfaces (profile/docs/settings) deferred until the repo is public. Co-Authored-By: Claude Opus 4.8 (1M context) --- .../2026-07-02.02-aiohttp-brand/design.md | 125 ++++++++++++++++++ 1 file changed, 125 insertions(+) create mode 100644 planning/changes/2026-07-02.02-aiohttp-brand/design.md diff --git a/planning/changes/2026-07-02.02-aiohttp-brand/design.md b/planning/changes/2026-07-02.02-aiohttp-brand/design.md new file mode 100644 index 0000000..2d1f937 --- /dev/null +++ b/planning/changes/2026-07-02.02-aiohttp-brand/design.md @@ -0,0 +1,125 @@ +--- +summary: Mint the modern-di-aiohttp brand mark (async event-loop in a gold disc) and generate its assets; public surfaces deferred until the repo ships. +--- + +# Design: modern-di-aiohttp brand mark + +## Summary + +`modern-di-aiohttp` is a new DI integration, still in development — its GitHub +repo is not public and the package is not on PyPI yet. This change mints its +brand mark (an **async event-loop cycle knocked out of a gold disc**) and +generates the six per-project asset files in this repo (`.github`), so they are +ready when the repo goes public. The public-facing surfaces (profile README row, +docs-site bullet, GitHub repo settings) are deliberately **deferred** — they +show PyPI/Downloads badges and link to a public repo that does not exist yet. + +## Motivation + +Every mainstream web-framework integration in the org has a brand mark +(`modern-di-fastapi` bolt-in-disc, `modern-di-litestar` star-in-disc, +`modern-di-starlette` sparkle). Preparing aiohttp's mark now means the asset +URLs resolve the moment its repo publishes its README, with no scramble. + +We reviewed aiohttp's real logo (a node/network graph inside a ring). We +deliberately did **not** adapt it: the node-graph motif is already how +`modern-di` and `that-depends` read in this same lineup, so a faithful copy +would collide. The chosen mark keeps the async meaning and joins the +disc-family (FastAPI/Litestar), which is visually distinct from the DI +graph marks. + +## Non-goals + +- No changes to the (not-yet-public) `modern-di-aiohttp` repo. +- **No** profile README row, docs-site bullet, or GitHub repo settings — these + wait until the repo is public (tracked under "Deferred follow-ups" below). +- No social card: integrations are not in `DOCS_REPOS`. + +## Design + +### 1. Async-loop symbol — `brand/build/symbols.py` + +Add `async_loop(cx, cy, r)`: two cream arrows chasing each other in a circular +loop (the universal "async / event-loop" cycle), knocked out of a gold disc. +It reuses the existing `_circ_arc` arc-with-arrowhead helper. + +`_circ_arc` currently hardcodes `GOLD` for both its stroke and its arrowhead +fill. Extend its signature with a trailing optional `color: str = GOLD` and +substitute `{color}` for the two `{GOLD}` occurrences. This is backward +compatible — the only existing caller (`db_retry`) omits the argument and keeps +`GOLD`. + +```python +def _circ_arc(cx: float, cy: float, rad: float, a0: float, a1: float, w: float, + color: str = GOLD) -> str: + ... # stroke and arrowhead now use {color} instead of {GOLD} + + +def async_loop(cx: float, cy: float, r: float) -> str: + """aiohttp cue: an async event-loop cycle (two chasing arrows) knocked out + of a gold disc.""" + rad = r * 0.52 + w = 3.4 + loop = ( + _circ_arc(cx, cy, rad, 25, 165, w, color=CREAM) + + _circ_arc(cx, cy, rad, 205, 345, w, color=CREAM) + ) + return f'' + loop +``` + +`CREAM` is already imported in `symbols.py`. The mark uses only `GOLD` and +`CREAM`, both in the allowed palette, so `test_only_allowed_colours` passes. + +### 2. Manifest entry — `brand/build/projects.py` + +Add `"modern-di-aiohttp": lambda: sym.async_loop(_CX, _CY, R)` to `MANIFEST`, +in the dependency-injection block, immediately after `modern-di-starlette` +(keeps the web-framework integrations fastapi -> litestar -> starlette -> +aiohttp adjacent). + +### 3. Test — `tests/test_projects.py` + +Add `"modern-di-aiohttp"` to `EXPECTED_REPOS`. That set is asserted equal to +`MANIFEST`, and the valid-SVG / allowed-colours / render tests are parametrized +off it, so no other test edits are required. `DOCS_EXPECTED` is unchanged. + +### 4. Regenerate assets — `just sync-assets` + +Produces `brand/projects/modern-di-aiohttp/{mark.svg, mark-512.png, +mark-1024.png, lockup-light.svg, lockup-dark.svg, lockup.png}`. Commit the +generated files. + +## Deferred follow-ups (when the repo is public) + +Ship these in a later change once `github.com/modern-python/modern-di-aiohttp` +exists and the package is on PyPI: + +- Profile README row in the Dependency injection table. +- Docs-site bullet in the DI list (+ mention in the stack sentence). +- GitHub repo settings: description `modern-di integration for aiohttp`, + homepage `https://modern-di.modern-python.org`, topics + `python, dependency-injection, di, ioc-container, modern-di, aiohttp`. + +The canonical one-liner for all of the above will be +`modern-di integration for aiohttp`. + +## Testing + +- `just test` green, in particular `tests/test_projects.py`: + `test_manifest_covers_every_repo`, `test_only_allowed_colours`, + `test_project_mark_is_valid_svg`, and the render tests. +- Visually inspect the regenerated `mark.svg` and light/dark lockups for the + aiohttp entry. +- `just sync-assets` re-run is a no-op diff apart from the six new files + (deterministic render). +- `just check-planning` passes before pushing. + +## Risk + +- **Low: async_loop reads too close to db-retry's retry arcs** (both are + arced arrows). Mitigated — db-retry is a single retry arc around a database + cylinder; async_loop is two symmetric arrows forming a closed cycle on a + plain disc. Different enough; confirmed against the rendered marks. +- **Low: extending `_circ_arc` breaks db-retry.** Mitigated — the new param is + optional and defaults to `GOLD`; the existing call is unchanged and the + palette test covers db-retry. From f227564b91c66934e37b2126ce98a3a4d217f150 Mon Sep 17 00:00:00 2001 From: Artur Shiriev Date: Thu, 2 Jul 2026 13:17:59 +0300 Subject: [PATCH 2/3] feat(brand): add async-loop mark for modern-di-aiohttp New async_loop symbol (event-loop cycle in a gold disc); _circ_arc gains an optional color param (default GOLD, backward compatible) so the loop arrows render in cream. Manifest + EXPECTED_REPOS entries after modern-di-starlette. Co-Authored-By: Claude Opus 4.8 (1M context) --- brand/build/projects.py | 1 + brand/build/symbols.py | 19 ++++++++++++++++--- tests/test_projects.py | 1 + 3 files changed, 18 insertions(+), 3 deletions(-) diff --git a/brand/build/projects.py b/brand/build/projects.py index ccce029..3a47edb 100644 --- a/brand/build/projects.py +++ b/brand/build/projects.py @@ -21,6 +21,7 @@ "modern-di-fastapi": lambda: sym.bolt_disc(_CX, _CY, R), "modern-di-litestar": lambda: sym.star_disc(_CX, _CY, R), "modern-di-starlette": lambda: sym.sparkle_cluster(_CX, _CY, R), + "modern-di-aiohttp": lambda: sym.async_loop(_CX, _CY, R), "modern-di-faststream": lambda: sym.faststream(_CX, _CY, R), "modern-di-typer": lambda: sym.terminal(_CX, _CY, R), "modern-di-pytest": lambda: sym.bars(_CX, _CY, R), diff --git a/brand/build/symbols.py b/brand/build/symbols.py index e538d8e..b48db14 100644 --- a/brand/build/symbols.py +++ b/brand/build/symbols.py @@ -84,7 +84,9 @@ def sparkle_cluster(cx: float, cy: float, r: float) -> str: return big + small -def _circ_arc(cx: float, cy: float, rad: float, a0: float, a1: float, w: float) -> str: +def _circ_arc( + cx: float, cy: float, rad: float, a0: float, a1: float, w: float, color: str = GOLD +) -> str: """Clockwise arc a0->a1 (deg, increasing) with a leading arrowhead at a1.""" a1s = a1 - 7 # stop the stroke short so the head caps it cleanly x0 = cx + rad * math.cos(math.radians(a0)) @@ -94,7 +96,7 @@ def _circ_arc(cx: float, cy: float, rad: float, a0: float, a1: float, w: float) large = 1 if (a1s - a0) % 360 > 180 else 0 d = ( f'' + f'fill="none" stroke="{color}" stroke-width="{w}" stroke-linecap="butt"/>' ) ex = cx + rad * math.cos(math.radians(a1)) ey = cy + rad * math.sin(math.radians(a1)) @@ -108,11 +110,22 @@ def _circ_arc(cx: float, cy: float, rad: float, a0: float, a1: float, w: float) d += ( f'' + f'{base[0] - width * px:.1f},{base[1] - width * py:.1f}" fill="{color}"/>' ) return d +def async_loop(cx: float, cy: float, r: float) -> str: + """aiohttp cue: an async event-loop cycle (two chasing arrows) knocked out + of a gold disc.""" + rad = r * 0.52 + w = 3.4 + loop = _circ_arc(cx, cy, rad, 25, 165, w, color=CREAM) + _circ_arc( + cx, cy, rad, 205, 345, w, color=CREAM + ) + return f'' + loop + + FASTSTREAM_PATH = ( "m499.61,356.87l-92.61-160.41-36.48-63.19-10.46,251.02c.07,2.86-.78,6.05-2.51,8.6" "-2.98,4.41-7.42,5.31-9.92,2.02l.02-.03-68.85-90.48-107.13,38.09v.04c-3.89,1.38-7.11" diff --git a/tests/test_projects.py b/tests/test_projects.py index 3a9f0d2..c93ee6c 100644 --- a/tests/test_projects.py +++ b/tests/test_projects.py @@ -21,6 +21,7 @@ def test_project_frame_parses_and_uses_tokens() -> None: "modern-di-fastapi", "modern-di-litestar", "modern-di-starlette", + "modern-di-aiohttp", "modern-di-faststream", "modern-di-typer", "modern-di-pytest", From f58fa4006e114ec6daf1b6176a921b67125c0f11 Mon Sep 17 00:00:00 2001 From: Artur Shiriev Date: Thu, 2 Jul 2026 13:18:39 +0300 Subject: [PATCH 3/3] chore(brand): generate modern-di-aiohttp assets Co-Authored-By: Claude Opus 4.8 (1M context) --- brand/projects/modern-di-aiohttp/lockup-dark.svg | 1 + .../projects/modern-di-aiohttp/lockup-light.svg | 1 + brand/projects/modern-di-aiohttp/lockup.png | Bin 0 -> 2074 bytes brand/projects/modern-di-aiohttp/mark-1024.png | Bin 0 -> 9592 bytes brand/projects/modern-di-aiohttp/mark-512.png | Bin 0 -> 4417 bytes brand/projects/modern-di-aiohttp/mark.svg | 1 + 6 files changed, 3 insertions(+) create mode 100644 brand/projects/modern-di-aiohttp/lockup-dark.svg create mode 100644 brand/projects/modern-di-aiohttp/lockup-light.svg create mode 100644 brand/projects/modern-di-aiohttp/lockup.png create mode 100644 brand/projects/modern-di-aiohttp/mark-1024.png create mode 100644 brand/projects/modern-di-aiohttp/mark-512.png create mode 100644 brand/projects/modern-di-aiohttp/mark.svg diff --git a/brand/projects/modern-di-aiohttp/lockup-dark.svg b/brand/projects/modern-di-aiohttp/lockup-dark.svg new file mode 100644 index 0000000..f3e7c88 --- /dev/null +++ b/brand/projects/modern-di-aiohttp/lockup-dark.svg @@ -0,0 +1 @@ + diff --git a/brand/projects/modern-di-aiohttp/lockup-light.svg b/brand/projects/modern-di-aiohttp/lockup-light.svg new file mode 100644 index 0000000..d7b06ba --- /dev/null +++ b/brand/projects/modern-di-aiohttp/lockup-light.svg @@ -0,0 +1 @@ + diff --git a/brand/projects/modern-di-aiohttp/lockup.png b/brand/projects/modern-di-aiohttp/lockup.png new file mode 100644 index 0000000000000000000000000000000000000000..495d32447aab7353e63e9bfa6334d780bfa3bc31 GIT binary patch literal 2074 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 literal 0 HcmV?d00001 diff --git a/brand/projects/modern-di-aiohttp/mark.svg b/brand/projects/modern-di-aiohttp/mark.svg new file mode 100644 index 0000000..7dcfdbd --- /dev/null +++ b/brand/projects/modern-di-aiohttp/mark.svg @@ -0,0 +1 @@ +