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
- A public
.aliases property on each AppType member.
__repr__ and __str__ expose the aliases when there are any.
- 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.
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:
(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
.aliasesproperty on eachAppTypemember.__repr__and__str__expose the aliases when there are any.Expected behavior
TCP['http'].aliasesgives the other services IANA registers on TCP/80 — andSCTP['http'].aliasesis empty, becausewwwis 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:__canonical__is a per-registryport → canonical servicemap curated from/etc/services, because IANA names no precedence and registry row order matches/etc/serviceson 28 of the 44 colliding pairs and differs on 16 (test_a_port_lookup_returns_the_canonical_serviceat:114records the reasoning;test_get_all_reaches_the_aliasesat:143is the existing reader).So
.aliasesneeds no new storage. It derives as__registry__.getlist(self.port)minusself— verified:Return an empty tuple rather than
Nonewhen 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_.AppTypeis aStrEnumand_value_is the live lookup key in_value2member_map_, built once at class creation. Mutating it afterwards leaves the map stale: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.valueisTruetoday and becomesFalse. 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/stroutput 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.