Protocol Member Order

The order of members inside a protocol class body. Settled by the owner on #2490, so a new dissector and a refactor land in the same layout.

Each group sits under its section comment, spelled as the repo spells it: # Properties., # Methods., # Data models. and # Utilities.

The Order

  1. Properties. Every @property member.

  2. Methods. Public methods: mostly id(), read(), make() and register_xxx().

  3. Data models. Every dunder name: __index__, __length_hint__, __init__, __new__, __post_init__ and any other.

  4. Utilities. Everything else, mostly private methods, in the subgroups below. Every private helper, including _check_*, sits here, never before _make_data().

    1. Data. _make_data() comes first in the group, before everything else.

    2. Helpers. The helpers that read() or make() call, one helper at a time, in the order read() or make() first uses them. “Uses” means a direct reference in the body of read() or make(). Helpers reached only through getattr, or through the registry maps (__proto__, __option__, __parameter__ and similar), do not count. They are ordered by the enum value order of the corresponding code, or by the registry’s order where there is no enum. A registry fallback that read() or make() names directly, such as _read_msg_unknown() in MH, does not count either: it is a specific reader, ruled on #2490. Each helper’s _read_ and _make_ methods stay together, with the reader first: _read_addr_resolve() then _make_addr_resolve().

    3. Specific readers and makers. The option, type and parameter methods, all _read_*() before all _make_*(). Each set opens with the registry’s default, its fallback for a code with no entry of its own, as _read_opt_unassigned() opens the readers of IPv4; the rest follow the enum value of the code or type each handles, not alphabetical order. Ruled on #2490.

    4. Other helpers. Every helper that read(), make() and the registries do not reach goes last, including one that only another helper calls, such as _decode_text() in HTTPv1. Ruled on #2490.

Registry maps. The registry maps themselves (__proto__, __option__, __parameter__ and similar) are ordered by their enum values, or alphabetically by key where there is no enum.

The guard. tests/project/test_protocol_member_order_2490_unit.py holds every protocol class to the groups, _make_data() first, each _read_xxx() before its _make_xxx(), and subgroup b, with a table of known exceptions (#2490).

Example

The utilities of ARP, reduced to its member names. read() resolves a hardware address before a protocol address, so the hardware pair comes first:

class ARP(Link[Data_ARP, Schema_ARP]):

    # Utilities.
    def _make_data(cls, data):                    # a. data first
        ...

    def _read_addr_resolve(self, addr, htype):    # b. first helper: reader ...
        ...

    def _make_addr_resolve(self, addr, htype):    # ... then its maker
        ...

    def _read_proto_resolve(self, addr, ptype):   # b. next helper: reader ...
        ...

    def _make_proto_resolve(self, addr, ptype):   # ... then its maker
        ...

The Reference

ARP is the reference for the utilities order. Its utilities are _make_data() and the helpers that read() and make() name, and nothing else, and there is more than one helper, so the first-use order of subgroup b shows as well as each reader preceding its maker. Chosen on #2614, when the MAC address pair of Ethernet, the reference before it, moved to the base class.