• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

aio-libs / multidict / 37223883328
86%

Build:
DEFAULT BRANCH: master
Ran 04 Oct 2026 06:18PM UTC
Jobs 1
Files 49
Run time 1min
Badge
Embed ▾
README BADGES
x

If you need to use a raster PNG badge, change the '.svg' to '.png' in the link

Markdown

Textile

RDoc

HTML

Rst

04 Oct 2026 06:17PM UTC coverage: 85.962%. Remained the same
37223883328

push

github

web-flow
Read the class at run time in the update() and merge() loops (#1675)

<!-- Thank you for your contribution! -->

## What do these changes do?

`bulk_update.h` compiled 22 copies of its loops: three sources
(multidict, dict, sequence) times three operations times two classes,
plus keyword arguments and self-extend per class.

This drops the per-class copies where the constructor does not depend on
them:

- `update()` and `merge()` keep one copy per source, which reads
`md->is_ci` at run time;
- `extend()` from another multidict, and from itself, likewise;
- `extend()` from a sequence, a dict and keyword arguments is the
constructor's path and keeps its per-class copies.

That leaves 13 copies. The `.text` section shrinks from 341.6 KB to
285.8 KB on 3.14 (-16.3%) and from 340.7 KB to 293.8 KB on 3.14t
(-13.8%).

A smaller unit gives GCC a smaller inlining budget, and on free-threaded
builds three hot paths lost a helper: the items iterator
(`Py_NewRef()`), `d[key] = v` (`_key_to_identity_cs()`) and `del d[key]`
on `CIMultiDict`. The iterator step and `md_ensure_key()` now take their
reference with `Py_INCREF()`, which CPython forces inline, and
`_key_to_identity_cs()` is `ALWAYS_INLINE` on free-threaded builds only,
with a `check_inlining.py` rule. Forced on GIL builds too, it cost the
constructor an instruction per item.

No behaviour change. The pure-Python implementation is not affected.

## Are there changes in behavior for the user?

No, apart from speed. Instructions per operation under callgrind, 3.14.7
and 3.14.7t, before and after:

| | GIL `MultiDict` | GIL `CIMultiDict` | FT `MultiDict` | FT
`CIMultiDict` |
| --- | --- | --- | --- | --- |
| `d.update(other)`, 100 existing keys (driver row) | +2.4% | 0.0% |
+2.8% | +0.4% |
| `update()`, 20-item source, from a multidict | +0.3% to +1.8% | +0.5%
to +0.7% | -0.6% to +1.2% | +0.5% to +0.6% |
| `update()`, from a list, a dict, keyword arguments | 0.0% to +1.2% |
0.0% to +0.3% | +0.1% to +1.9% | -0... (continued)

792 of 1584 branches covered (50.0%)

Branch coverage included in aggregate %.

9324 of 10184 relevant lines covered (91.56%)

1.83 hits per line

Jobs
ID Job ID Ran Files Coverage
1 MyPy - 37223883328.1 04 Oct 2026 06:18PM UTC 98
85.96
GitHub Action Run
Source Files on build 37223883328
  • Tree
  • List 49
  • Changed 2
  • Source Changed 0
  • Coverage Changed 2
Coverage ∆ File Lines Relevant Covered Missed Hits/Line Branch Hits Branch Misses
  • Back to Repo
  • Github Actions Build #37223883328
  • 5630f174 on github
  • Prev Build on master (#37220670984)
  • Next Build on master (#37224964410)
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE TRIAL · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc