All three public registration entry points refuse the library's own classes. Reproduced in a clean process against 27bb315d5:
register_extractor_engine('zzz_e', 'pcapkit.foundation.engines.pcap', 'PCAP')
-> RegistryError: engine must be an Engine subclass, not <class '...pcap.PCAP'>
register_extractor_reassembly('zzz_r', 'pcapkit.foundation.reassembly.ipv4', 'IPv4')
-> RegistryError: reassembly must be a Reassembly subclass, not <class '...ipv4.IPv4'>
register_extractor_traceflow('zzz_t', 'pcapkit.foundation.traceflow.tcp', 'TCP')
-> RegistryError: traceflow must be a TraceFlow subclass, not <class '...tcp.TCP'>
Cause
The validations at pcapkit/foundation/extraction.py:390, :412 and :434 test issubclass(x, Engine | Reassembly | TraceFlow) — the auto-registering public classes. But every built-in subclasses the *Base variant, imported under a local alias:
pcapkit/foundation/engines/pcap.py:13 — from ...engine import EngineBase as Engine
pcapkit/foundation/reassembly/ip.py:22 — ReassemblyBase as Reassembly
pcapkit/foundation/traceflow/tcp.py:16 — TraceFlowBase as TraceFlow
Measured:
issubclass(PCAP, Engine) : False
issubclass(PCAP, EngineBase) : True
Descendant counts across the whole package make it clear this is universal, not incidental:
| public class |
descendants |
base class |
descendants |
Protocol |
0 |
ProtocolBase |
43 |
Engine |
0 |
EngineBase |
9 |
Reassembly |
0 |
ReassemblyBase |
5 |
TraceFlow |
0 |
TraceFlowBase |
2 |
The aliasing is deliberate — subclassing the public class would auto-register the built-ins via __init_subclass__ — but it makes the validation stricter than the type hints and docstrings promise.
Suggested fix
Name EngineBase / ReassemblyBase / TraceFlowBase in those three issubclass checks. That accepts both the built-ins and any external subclass (a Protocol subclass is also a ProtocolBase), so it only widens.
Related: the same public-vs-base confusion left a branch dead for three years in #506 (schema/schema.py checked isinstance(data, Protocol) where it meant ProtocolBase), and the underlying design question is filed separately.
All three public registration entry points refuse the library's own classes. Reproduced in a clean process against
27bb315d5:Cause
The validations at
pcapkit/foundation/extraction.py:390,:412and:434testissubclass(x, Engine | Reassembly | TraceFlow)— the auto-registering public classes. But every built-in subclasses the*Basevariant, imported under a local alias:pcapkit/foundation/engines/pcap.py:13—from ...engine import EngineBase as Enginepcapkit/foundation/reassembly/ip.py:22—ReassemblyBase as Reassemblypcapkit/foundation/traceflow/tcp.py:16—TraceFlowBase as TraceFlowMeasured:
Descendant counts across the whole package make it clear this is universal, not incidental:
ProtocolProtocolBaseEngineEngineBaseReassemblyReassemblyBaseTraceFlowTraceFlowBaseThe aliasing is deliberate — subclassing the public class would auto-register the built-ins via
__init_subclass__— but it makes the validation stricter than the type hints and docstrings promise.Suggested fix
Name
EngineBase/ReassemblyBase/TraceFlowBasein those threeissubclasschecks. That accepts both the built-ins and any external subclass (aProtocolsubclass is also aProtocolBase), so it only widens.Related: the same public-vs-base confusion left a branch dead for three years in #506 (
schema/schema.pycheckedisinstance(data, Protocol)where it meantProtocolBase), and the underlying design question is filed separately.