Is your feature request related to a problem? Please describe.
Every registry under pcapkit/const/ turns an unrecognised value into a permanently registered enum member via aenum.extend_enum, so a process that parses many distinct unassigned values grows its registries without bound. #575 measured the cost on one path — 111 calls and ~13.5% of extraction self time on http.pcap — but the mechanism is repo-wide.
The maintainer's ruling, verbatim: "i think we should even apply to all other Enum's legit but unbounded values - so that we dont create registered enums out of unrecognised/unregistered values, unless user/caller explicitly created them."
Describe the solution you'd like
Return an unregistered member of the namespace class instead of minting. Measured as viable on AppType:
obj = str.__new__(TCP, 'unassigned')
obj._name_ = 'unassigned'; obj._value_ = 'unassigned'
obj.port = 54321; obj.svc = 'unknown'; obj.proto = TransportProtocol.tcp
repr : <TCP.unknown: 54321 [tcp]>
isinstance TCP : True
registry grew : 6147 -> 6147 members, 6147 -> 6147 values
It satisfies isinstance, reprs identically to a declared member, and does not grow the registry. Note AppType is a StrEnum (TCP → AppType → StrEnum → str → ReprEnum), so it is str.__new__; an int-valued registry needs int.__new__ instead, and int.__new__(TCP, …) raises TypeError: TCP is not a subtype of int.
Scope, measured by AST over pcapkit/const/
extend_enum inside _missing_ : 1056 calls across 113 files
extend_enum inside get() : 113 calls across 112 files
1,169 sites across 113 registries. Both paths mint per value — including the _missing_ declared-range branches, which is not obvious:
TCP.get(49100) -> <TCP.unassigned: 49100 [undefined]> members 6147 -> 6148
TCP.get(49101) -> <TCP.unassigned: 49101 [undefined]> members 6148 -> 6149
LinkType(60000) -> <LinkType.Unassigned_60000: 60000> members 220 -> 221
Those branches are bounded in which ranges they cover, not in how many members they create.
Additional context
#771 implements this for the four EnumField subclasses only — the parse path, where the measured cost is — and closes #575. This issue is the rest.
Three questions to settle before a wide change, none resolved: a value-lookup like TCP(54321) stays failing since the instance is absent from _value2member_map_; AppType.__eq__/__hash__ key on .port, so two unregistered instances for one port compare equal without being identical; and pickling or copying an unregistered member may not survive. Also open is whether this belongs in each registry's _missing_ — where aenum naturally hooks and where 1,056 of the sites are — rather than at the field layer. The ruling's "unless user/caller explicitly created them" means a direct get() call may still register; only paths that never asked for a name should get the unregistered member.
Is your feature request related to a problem? Please describe.
Every registry under
pcapkit/const/turns an unrecognised value into a permanently registered enum member viaaenum.extend_enum, so a process that parses many distinct unassigned values grows its registries without bound. #575 measured the cost on one path — 111 calls and ~13.5% of extraction self time onhttp.pcap— but the mechanism is repo-wide.The maintainer's ruling, verbatim: "i think we should even apply to all other Enum's legit but unbounded values - so that we dont create registered enums out of unrecognised/unregistered values, unless user/caller explicitly created them."
Describe the solution you'd like
Return an unregistered member of the namespace class instead of minting. Measured as viable on
AppType:It satisfies
isinstance, reprs identically to a declared member, and does not grow the registry. NoteAppTypeis aStrEnum(TCP → AppType → StrEnum → str → ReprEnum), so it isstr.__new__; an int-valued registry needsint.__new__instead, andint.__new__(TCP, …)raisesTypeError: TCP is not a subtype of int.Scope, measured by AST over
pcapkit/const/1,169 sites across 113 registries. Both paths mint per value — including the
_missing_declared-range branches, which is not obvious:Those branches are bounded in which ranges they cover, not in how many members they create.
Additional context
#771 implements this for the four
EnumFieldsubclasses only — the parse path, where the measured cost is — and closes #575. This issue is the rest.Three questions to settle before a wide change, none resolved: a value-lookup like
TCP(54321)stays failing since the instance is absent from_value2member_map_;AppType.__eq__/__hash__key on.port, so two unregistered instances for one port compare equal without being identical; and pickling or copying an unregistered member may not survive. Also open is whether this belongs in each registry's_missing_— whereaenumnaturally hooks and where 1,056 of the sites are — rather than at the field layer. The ruling's "unless user/caller explicitly created them" means a directget()call may still register; only paths that never asked for a name should get the unregistered member.