Skip to content

reg: expose AppType aliases as a public property and in repr/str, and allow registering them per transport #807

Description

@JarryShaw

Is this a bug or a feature request? A feature, ruled on in #801.

Step 2 of #801's three. The maintainer's rulings, verbatim:

and maybe allow aliasing, like register_apptype(port: int, name: str, *transport: TransportProtocol, aliases: list[str] = None), where aliases is an optional keyword argument using name as the canonical name with aliases for the port's aliases like port 80's.

alias should thus be per-transport. and we should probably allow registering aliases for a given enum in the transport apptype enum.

and on each apptype enum's repr/str, it should expose its associated aliases (if any) as well. And the enum should also have a public property/member to fetch its aliases list.

(He also noted his signature sketches are "just POC not how it should actually look like", so treat the shape as the requirement and the parameter list as illustrative.)

What changes

  1. A public .aliases property on each AppType member.
  2. __repr__ and __str__ expose the aliases when there are any.
  3. A way to register an alias on a per-transport registry.

Expected behavior

TCP['http'].aliases gives the other services IANA registers on TCP/80 — and SCTP['http'].aliases is empty, because www is not registered on SCTP. Aliases are a property of (port, transport), never of the port alone.

Additional context

Most of this already exists — check before building. Reading tests/const/test_const_apptype_split_unit.py (415 lines, 15 methods) shows the canonical/alias split is already implemented and tested:

TCP.__canonical__ entries = 23    UDP = 21    SCTP = 0    DCCP = 0
TCP.get(80).svc      = http                   <- canonical
TCP.get_all(80) svcs = ['http', 'www', 'www-http']
TCP.http == TCP.www  = True   (is: False)     <- equal and same hash, distinct members

__canonical__ is a per-registry port → canonical service map curated from /etc/services, because IANA names no precedence and registry row order matches /etc/services on 28 of the 44 colliding pairs and differs on 16 (test_a_port_lookup_returns_the_canonical_service at :114 records the reasoning; test_get_all_reaches_the_aliases at :143 is the existing reader).

So .aliases needs no new storage. It derives as __registry__.getlist(self.port) minus self — verified:

derived aliases of TCP.http -> ['www', 'www-http']
derived aliases of TCP.www  -> ['http', 'www-http']

Return an empty tuple rather than None when there are none, so callers need no guard, and a tuple rather than a list because members are otherwise immutable.

Hard constraint, measured: the aliases must NOT reach _value_. AppType is a StrEnum and _value_ is the live lookup key in _value2member_map_, built once at class creation. Mutating it afterwards leaves the map stale:

TCP('http [80 - tcp|udp|sctp]') is TCP['http'] -> True
after mutating _value_:  TCP(old) -> still resolves ; TCP(new) -> ValueError: not a valid TCP

Since aliases are registerable at runtime, an alias list inside _value_ goes stale the moment one is registered. So __repr__/__str__ grow them and _value_ does not.

Two consequences to handle rather than discover:

  • str(m) == m.value is True today and becomes False. 0 tests or docs pin the bracketed value form — verified with a self-tested pattern (grep -rnE "\[[0-9]+ - (tcp|udp|sctp|dccp)" tests/ docs/source/ examples/ → 0, and the same pattern matches the real string, so the zero is real).
  • repr/str output becomes mutable at runtime, since registering an alias changes it. Note that in the docstring so nobody pins a fixed alias list in a doctest.

Related: #801, #806, #732.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions