Skip to content

refactor(corekit)!: Info.to_dict() returns an OrderedMultiDict; add MultiInfo and OrderedMultiInfo to infoclass #1484

Closed

Description

@JarryShaw

Is your feature request related to a problem? Please describe.
Info.to_dict() returns InfoDict (pcapkit/corekit/multidict.py:643, added by #1466). Measured on 00d232890 with an IPv6 packet carrying two Destination Options headers:

  • It is mutable: setting a key, add() and del all succeed, whereas Info refuses assignment with UnsupportedCall.
  • No attribute access: d.limit and d['opts'].next raise AttributeError, while info.limit works.
  • Dumps drop the repeated key: the JSON, tree and plist dumps each hold opts once, losing the second header. dumpkit/common.py:451,462 excludes InfoDict from the code that writes every value.
  • Wrong home: multidict.py copies Werkzeug's source, so an Info-specific class does not belong there.

Describe the solution you'd like
Per the owner, a MultiInfo class in pcapkit/corekit/infoclass.py replaces InfoDict:

  • to_dict() returns it;
  • it is immutable, with keys readable as attributes, like Info;
  • it keeps every value of a repeated key;
  • it builds on the multidict classes without editing that module;
  • the dumpers write every value of a repeated key.

from_dict(to_dict()) == info and the byte-exact rebuild must keep passing.

Open question: which base class. Werkzeug's MultiDict groups values by key and so loses the order of different keys. For an IPv6 chain of Opts, Route, Opts it yields opts, opts, route, and IPv6.from_data() then raises AttributeError: 'IPv6_Route' object has no attribute 'type'. OrderedMultiDict keeps the order on the wire and rebuilds byte-exactly. So MultiInfo needs OrderedMultiDict's ordering, whether by subclassing it or by reproducing that ordering on top of MultiDict.

Describe alternatives you've considered
Keeping InfoDict and fixing only the dumpers. Its mutability and missing attribute access would remain.

Additional context
InfoDict came from #1453/#1466. Whether to rename infoclass to info is tracked in #1485.

Activity

  1. added
    breakingBreaks public-facing behaviour or API (apply alongside the type label)
    refactorRestructuring for its own sake — neither a fix nor a new capability (refactor: prefix)
    needs: decisionWaiting on the maintainer to decide — not blocked by other work
    on Oct 9, 2026
  2. moved this to Needs decision in PyPCAPKiton Oct 9, 2026
  3. JarryShaw commented on Oct 9, 2026

    @JarryShaw
    OwnerAuthor

    I recall Info.to_dict was supposed to return a dict-like object directly. So returning an Info-like object here seems off the track.

    We definitely would need MultiInfo and OrderedMultiInfo for other use cases for sure. But Info.to_dict should still return dict or MultiDict or OrderedMultiDict in my opinion.

  4. JarryShaw commented on Oct 9, 2026

    @JarryShaw
    OwnerAuthor

    Recorded: the owner wants Info.to_dict() to return a plain dict type, a dict, MultiDict or OrderedMultiDict, not something Info-like. MultiInfo and OrderedMultiInfo are still wanted, for other uses. The revised scope:

    1. to_dict() returns OrderedMultiDict. The order matters: for an IPv6 chain Opts, Route, Opts, a MultiDict groups it as opts, opts, route and IPv6.from_data() raises, while OrderedMultiDict rebuilds byte-exactly.
    2. Remove InfoDict. That puts pcapkit/corekit/multidict.py back to the Werkzeug-derived classes only. The dumpers already write every value of an OrderedMultiDict (dumpkit/common.py:451), so the repeated header returns to the JSON, tree and plist output.
    3. Add MultiInfo and OrderedMultiInfo to pcapkit/corekit/infoclass.py. They are immutable, attribute-accessible and keep repeated keys, building on the multidict classes without editing them.

    from_dict(to_dict()) == info and the byte-exact rebuild must still pass. This is still breaking, because to_dict()'s return type and its dict-interface semantics change.

    Labelled pending. I'll start it once the #1202 corekit slice reports, because that slice is measuring Info ↔ dict on the current InfoDict.

  5. removed
    needs: decisionWaiting on the maintainer to decide — not blocked by other work
    on Oct 9, 2026
  6. changed the title [-]refactor(corekit)!: replace InfoDict with an immutable, attribute-accessible MultiInfo in infoclass[/-] [+]refactor(corekit)!: Info.to_dict() returns an OrderedMultiDict; add MultiInfo and OrderedMultiInfo to infoclass[/+] on Oct 9, 2026
  7. added
    pendingAccepted and unstarted - nobody is on it and nothing blocks it
    on Oct 9, 2026
  8. moved this from Needs decision to Pending in PyPCAPKiton Oct 9, 2026
  9. JarryShaw commented on Oct 9, 2026

    @JarryShaw
    OwnerAuthor

    and one additional note, I think those parsed option lists where I suppose we used MultiDict or OrderedMultiDict to hold the wip data, we should convert them to MultiInfo and OrderedMultiInfo respectively when finalising as Info.

  10. JarryShaw commented on Oct 9, 2026

    @JarryShaw
    OwnerAuthor

    Recorded, as a fourth scope item. Option lists are built as MultiDict or OrderedMultiDict while a packet is parsed. When the Info is finalised, they should become MultiInfo or OrderedMultiInfo respectively, so a finalised Info holds no mutable mapping.

    Measured on 00d232890:

    • Construction sites: 26 OrderedMultiDict( and 4 MultiDict( in pcapkit/protocols. The OrderedMultiDict( ones span 12 files: HTTP/1, HIP, HOPOPT, IPv4, IPv6, IPv6-Opts, MH, PCAP-NG, SCTP, TCP, and the IPv4 and PCAP-NG schemas.
    • Annotations: 106 OrderedMultiDict[...] annotations in pcapkit/protocols/data/, all to be retyped.
    • Round trip: to_dict() must turn a MultiInfo or OrderedMultiInfo field back into a plain MultiDict or OrderedMultiDict, and from_dict() must restore the *Info type, so the round trip stays byte-exact.

    It stays pending, starting after the #1202 corekit slice.

  11. JarryShaw commented on Oct 9, 2026

    @JarryShaw
    OwnerAuthor

    Blocked until #1492 merges and the #1490 fix has landed. All three touch pcapkit/corekit/infoclass.py, and #1490 changes how Info subclasses are finalised, which MultiInfo and OrderedMultiInfo build on.

  12. removed
    pendingAccepted and unstarted - nobody is on it and nothing blocks it
    on Oct 9, 2026
  13. 2 remaining items

  14. added
    wipWork in flight - a covering PR is open or an agent is actively on it
    and removed
    blockedDeferred pending another issue or decision; see the last comment for what unblocks it
    on Oct 9, 2026
  15. moved this from Blocked to WIP in PyPCAPKiton Oct 9, 2026
  16. added
    needs: decisionWaiting on the maintainer to decide — not blocked by other work
    on Oct 9, 2026
  17. JarryShaw commented on Oct 10, 2026

    @JarryShaw
    OwnerAuthor

    Both open questions are answered on #1523. MultiInfo and OrderedMultiInfo become real Info subclasses (option 1). For __ne__, multidict.py stays verbatim and to_dict() returns a thin subclass that adds __ne__ (option 3). The worker is implementing the second on #1523.

  18. removed
    needs: decisionWaiting on the maintainer to decide — not blocked by other work
    on Oct 10, 2026
  19. removed
    wipWork in flight - a covering PR is open or an agent is actively on it
    on Oct 10, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    breakingBreaks public-facing behaviour or API (apply alongside the type label)refactorRestructuring for its own sake — neither a fix nor a new capability (refactor: prefix)

    Projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions