Fixed
- Closed a decode-throughput regression against dpkt that nobody had
been watching tier over tier (#147). Re-measuring every held claim
after #107/#124 closed showed netprotocols had gone from 1.16× faster
than dpkt right after Tier 1 to ~11% slower after Tiers 2-4 — a
reversal none of the five tiers' own re-measurements had caught,
because none of them profiled, only re-measured before/after.
cProfileagainst the corpus decode loop found two causes, neither
of them the tiers first suspected:bytes_to_ipv6(added by #99 for
Pyodide portability, not one of the three tiers originally named)
formatted its eight address words one f-string at a time through a
generator, ~18% of total corpus decode time;decode_frame()'s
Packetconstruction paid a redundantisinstancecheck, through
Protocol's ABC machinery, on a list already guaranteed to hold only
Protocolinstances, ~7-8% ofdecode_frame()'s own time. Both
fixed without changing observable behavior:bytes_to_ipv6now
formats all eight words in one%-format call (verified
byte-identical against glibc'sinet_ntopvia the existing
hypothesis test, 2.1× faster in isolation);Packetgained an
internal_from_decoded()fast-construction path, used only by
decode_frame()— the publicPacket(...)constructor still
validates arbitrary arguments exactly as before. scripts/benchmark.pynow measuresdecode_frame(), the
documented public chain-walking API, instead of a hand-rolled loop
that predated it (#147). The benchmark'sdecode_netprotocols()
kept its own copy of the pre-#88 walk loop, never updated when
decode_frame()shipped, so every decode-throughput figure this
project has published — including every number indocs/CLAIMS.md
section 1 before this release — described code the documented API's
callers never actually ran.benchmarks/baseline.json, five tiers
and this fix stale at a v1.3.0-era figure, was refreshed to match.
See docs/CLAIMS.md's "Re-measured after closing the
dpkt-throughput regression" section for the full profiling writeup,
before/after numbers under both the old and new benchmark
methodology, and updated 1.1/1.2/1.6 figures.
Development
- Addressed CodeFactor's static-analysis findings on the tooling
scripts (#156).scripts/pyodide/check_in_pyodide.pyextracted
the built wheel into a hardcoded, predictable/tmp/netprotocols- wheelpath; it now usestempfile.mkdtemp(), verified against a
real Pyodide runtime (node scripts/pyodide/run_in_pyodide.mjs)
decoding the full corpus unchanged.scripts/check_fixtures.py's
_check_l3— one 137-line function walking IPv4, IPv6, GRE
tunneling, VLAN and every upper-layer checksum — is split into one
small function per protocol; output is byte-identical on the full
97-frame fixture corpus before and after.scripts/benchmark.py's
three broadexcept Exception: continueblocks are unchanged but
now documented:dpktandscapyhave no shared "malformed frame"
exception the way this project's ownProtocolErrordoes, so a
bareexceptis the correct interop boundary, not a swallowed bug.
The flagged duplication betweenbenchmark.pyand
check_in_pyodide.py's minimal pcap readers — nearly byte-identical
read_pcap/corpus_framesfunctions — is now shared via a new
scripts/_pcap.py. An initial pass left the duplication in place,
reasoning both scripts' docstrings required each verification path
to stand fully independent of the others; re-reading them shows that
claim is narrower than stated — "standalone" there means not
depending on netprotocols (the thing each script verifies), the same
usageCONTRIBUTING.mdandcheck_fixtures.py's own docstring use,
never independence from sibling scripts._pcap.pyis itself
stdlib-only and does not import netprotocols, so it preserves the
property the docstrings actually document. Verified against a real
Pyodide runtime after the extraction: the corpus still decodes
unchanged, andcheck_fixtures.py's own, materially different
read_pcap(it additionally validates linktype and length) is
untouched, since it was never part of this duplication.
Documentation
- Corrected six README.md claims an independent audit against the
live repo found stale or overstated, none of them accidental
regressions — each had simply drifted from what it once described.
Wheel size (85.6 KB / ~30× smaller than scapy) was measured against
the2.0.0wheel, two releases behind; rebuilt fromHEAD, it's
88.3 KB / ~29× (docs/CLAIMS.md§1.5 corrected to match). The typing
bullet's "107 of [scapy's] files" enable strict mypy checking was a
rawwc -lover scapy's enabled-files list including blank lines
and comments; filtered the way scapy's own tooling does, it's 89
(docs/CLAIMS.md§2.1 corrected, with the mismeasurement documented
so it doesn't recur). The Pyodide/browser bullet credited "dpkt and
pypacker import cleanly" to the real-Pyodide CI job; that job only
ever imports netprotocols under Pyodide (confirmed by reading
scripts/pyodide/check_in_pyodide.py) — the dpkt/pypacker rows come
from a separatesys.meta_path-blocklist simulation under ordinary
CPython, not from CI (docs/CLAIMS.md§3.1 reworded to say so
explicitly). The CI-gating bullet's closing clause, "the rest have no
performance benchmark at all," was contradicted by the very citation
it points to —docs/CLAIMS.md§1.7 documents that scapy and
PyTCP-net_proto do ship benchmark scripts, just not CI-wired; reworded
to the claim the table actually supports (none of the ten gates on
a regression). The Contributing section's "pytest,mypy, and
ruff check— all three are enforced by CI on Python 3.12-3.14"
overstated the matrix: onlypytestruns on 3.12-3.14;mypyand
ruff checkeach run on 3.12 only. The Roadmap section's "everything
through 2.2.0 has landed onmaster" didn't mention that a further,
unreleased fix (#147) has since landed on top of 2.2.0 — added a
clause naming it. A seventh finding — the Roadmap's claim that "only
2.0.0 was an actual PyPI release" — is contradicted by PyPI itself
(2.2.0, and in fact five earlier minor/patch versions, are also
published there); left unfixed pending a maintainer decision on
whether 2.2.0's publication was intentional, since fixing the prose
first would paper over a real process question. - Resolved the seventh finding above: 2.2.0's PyPI publication was
confirmed intentional. The Roadmap section's "per the roadmap's own
release policy, only 2.0.0 was an actual PyPI release" is now
"the roadmap's original 'only at a major version bump' release policy
wasn't actually held to: both 2.0.0 and 2.2.0 — a minor release — are
on PyPI," and the roadmap table's 2.2.0 row gained the same
released marker 2.0.0 already carried. Issue #107, the source
both docs draw this from, updated its own stated policy line with a
dated correction rather than silently rewriting history. - A fresh independent audit for #101 found four more genuine drifts
and fixed them, none of them regressions — just the register falling
behind a codebase and a README that both kept moving.docs/CLAIMS.md
§5.3's statement count (1,935) had drifted from the live count of
2,091 as the codebase grew — the coverage percentage held steady only
because the miss count never moved, masking it;pyproject.toml's own
inline comment was still quoting an even older 1,441 and is now
corrected too. §5.7's "79 tests" fortests/test_walk.pyundercounted
the live 85: one test parametrized over the corpus's first 40 frames
now collects its full 40 instances because the corpus has since grown
past that slice, not because tests were added. §1.6 overstated its own
claim about README.md, saying the decode-depth figure travels with the
throughput figure "in the same sentence" there; they're adjacent
bullets, not one sentence — corrected. README's Pyodide/browser bullet
said outright that "pypacker was not tested", contradicted by
docs/CLAIMS.md§3.1's own simulation table two paragraphs away, which
shows pypacker importing cleanly under the identical CPython-side
check used for dpkt; reworded to say so, and to stop implying the
scapy-import failure was observed directly inside the real Pyodide CI
run rather than established by source citation plus that simulation.
README's CI-gating bullet lumped PyTCP-net_proto in with three
libraries whose benchmark code targets the library being compared;
docs/CLAIMS.md§1.7's own citation notes PyTCP-net_proto's benchmark
exercises its RX daemon instead — reworded to keep that distinction
rather than flattening it. - Restored this file's own missing
## [2.2.0]version header. A
prior documentation commit deleted it while inserting an adjacent
bullet, which silently re-merged the entire tagged, PyPI-published
2.2.0 release back under## [Unreleased]— the section below is
what agit showof thev2.2.0tag's own CHANGELOG.md actually
contained at release time.