Repository navigation
Seven register/issubclass guards in the protocol classes still leak a bare TypeError for a non-class #1026
Description
Activity
- addedfixPull requests that fix a defect (fix: subject prefix)Pull requests that fix a defect (fix: subject prefix)
on Oct 5, 2026 - added a commit that references this issue
on Oct 5, 2026 - addedwipWork in flight - a covering PR is open or an agent is actively on itWork in flight - a covering PR is open or an agent is actively on it
on Oct 5, 2026 - added a commit that references this issue
on Oct 5, 2026 Correcting this issue's own premise:
Transport.registeris not exempt, so this is seven sites and not six.I wrote that
Transport.registerraisesUnsupportedCallbefore its guard is reachable. That is only true of the abstract class. The guard atpcapkit/protocols/transport/transport.py:109readsif cls is Transport:, so theUnsupportedCallfires for a literalTransport.registercall and for nothing else — andTransport.registeris never called that way. Measured on the current tree:Transport.register -> UnsupportedCall | transport.py:110 TCP.register -> TypeError | <frozen abc>:123 UDP.register -> TypeError | <frozen abc>:123So the bare
issubclassattransport.py:114is reachable through every concrete transport subclass, which is the only way it is ever reached in practice, and it leaks exactly like the other six. The list isProtocolBase.register,Frame.register,PCAPNG.register,SCTP.register,Link.register,Internet.registerandTransport.register— seven of the thirteenif not issubclasssites in the package, with six fixed in #1025.This matters beyond the count: a reader of the old wording would conclude
TCP.registerandUDP.registerwere already safe. The same wrong claim was in #1025's commit message and changelog entry and has been corrected there too.Worth noting for whoever takes this: the per-site judgement in the issue body still stands, and
Transport.registeradds a wrinkle to it. ItsRaises:prose needs reading alongside thecls is Transportgate, because the honest documentation has to say which exception a caller gets for which class.- removedwipWork in flight - a covering PR is open or an agent is actively on itWork in flight - a covering PR is open or an agent is actively on it
on Oct 5, 2026
Metadata
Metadata
Assignees
Labels
Projects
- StatusShow more project fieldsDone
All seven
registerclassmethods inpcapkit/protocols/carry a bareif not issubclass(x, ProtocolBase):with noisinstance(x, type)ahead of it, so a non-class argument is rejected byissubclassbefore the guard's ownraiseis reached and the caller getsTypeError: issubclass() arg 1 must be a classleaked out ofabcinstead of the library's own exception.Measured on
main, raise site read offtraceback.extract_tb(...)[-1]rather than off the message:pcapkit/protocols/protocol.py:768ProtocolBase.registerpcapkit/protocols/misc/pcap/frame.py:151Frame.registerpcapkit/protocols/misc/pcapng.py:919PCAPNG.registerpcapkit/protocols/transport/sctp.py:628SCTP.registerpcapkit/protocols/link/link.py:143Link.registerpcapkit/protocols/internet/internet.py:163Internet.registerpcapkit/protocols/transport/transport.py:114Transport.registerTransport.registeris included, and an earlier version of this body wrongly excluded it. ItsUnsupportedCallattransport.py:110is gated onif cls is Transport:, so it fires only for a literal call on the abstract class — which is never how it is reached. The guard below it leaks through the concrete subclasses:grep -rn "if not issubclass" pcapkit/finds 13 sites: six are fixed in #1025, and these seven remain.The per-site question
The maintainer's ruling on #1021 was "code follows prose": add an explicit class check so callers get the registry's own exception. That ruling was scoped to the
register_*module functions, and these are a different surface —registerclassmethods on protocol classes, keyed by code.Measured: all seven
Raises:clauses already promiseRegistryErrorfor "not a … subclass", and none says "class" explicitly. So the fix is a correction rather than a contract addition, on the reading that anintis not a subclass of anything — but the wording is ambiguous enough that each clause wants rewording to "is not a class, or not a … subclass" alongside the code change.Two inconsistencies worth settling in the same pass, both pre-existing: the
Raises:prose alternates between promising aProtocolsubclass and aProtocolBasesubclass across these seven sites, while every runtime message says "Protocol subclass" and every guard checksProtocolBase. That is the same conflation #514 is about, so the guard targets should not move here — only the prose should stop contradicting itself.Not breaking when fixed:
RegistryErrorsubclassesTypeErrorthroughBaseError, soexcept TypeErrorkeeps working and only code matching the exact type or the old message text sees a difference.Worth doing as one change rather than seven, since the fix is mechanical and the tests are parallel. Related: #1021, #1025, #514.