IPv6Address ordering is scope-id-blind, breaking trichotomy and making sorted()/min()/max() non-deterministic for scoped addresses
Dieses Issue hat noch niemand übernommen.
- Vorherrschende Sprache
- Python
- Sterne
- 77.2k
- Forks
- 35.9k
- PR-Merge-Kennzahlen
- PR-Kennzahlen ausstehend
Beschreibung
Bug report
Bug description:
COMPONENT: Library (Lib/ipaddress.py)
AFFECTED VERSIONS: main (3.16.0a0) and 3.14 (reproduced on 3.14.6). The defect dates to when scope_id was added to IPv6Address.__eq__/__hash__/__str__ but not to ordering.
SUMMARY
IPv6Address.__eq__ and __hash__ fold in the interface scope_id (so fe80::1 and fe80::1%eth0 are unequal and hash differently), but IPv6Address does not override ordering — it inherits _BaseAddress.__lt__, which compares only the integer address and ignores _scope_id. _BaseAddress is decorated with @functools.total_ordering, which synthesizes __gt__/__le__/__ge__ from __lt__ and __eq__. The synthesized __gt__ is effectively not (a < b) and a != b. For two addresses with the same integer but different scope, a < b is False (scope-blind __lt__) while a != b is True (scope-aware __eq__), so a > b is True — and symmetrically b > a is also True. The relation is not a strict order: trichotomy and antisymmetry both fail, and sorting is non-deterministic.
MINIMAL REPRODUCTION
>>> import ipaddress
>>> a = ipaddress.ip_address('fe80::1')
>>> b = ipaddress.ip_address('fe80::1%eth0')
>>> a == b
False
>>> a > b
True
>>> b > a # antisymmetry violated: both directions are "greater"
True
>>> from itertools import permutations
>>> items = [ipaddress.ip_address(s)
... for s in ('fe80::1', 'fe80::1%eth0', 'fe80::1%eth1')]
>>> {tuple(str(x) for x in sorted(p)) for p in permutations(items)}
# 6 DISTINCT outputs — sorted() just returns the input order
ROOT CAUSE
scope_id was added to IPv6Address.__eq__/__hash__/__str__ but not to ordering, and IPv6Address defines no __lt__. The @functools.total_ordering operators on _BaseAddress dispatch through type(self).__lt__, which (absent an override) resolves to the scope-blind _BaseAddress.__lt__ while total_ordering also consults the scope-aware __eq__ — so they disagree. The functools docs note total_ordering "makes no attempt to override methods declared in the class or its superclasses," which is exactly why the subclass inherits a __lt__ inconsistent with its own __eq__.
The minimal fix is a scope-aware IPv6Address.__lt__ (tie-break on scope_id only when the integer address is equal; unscoped sorts before scoped; scope ids compare lexicographically). Because the derived operators dispatch through type(self).__lt__, overriding only __lt__ on the subclass routes all four comparisons through the scope-aware path. This also transitively repairs scoped IPv6Interface and IPv6Network ordering, which delegate to address comparison. _BaseAddress.__lt__ is untouched, so IPv4Address is unaffected.
RELATION TO CONCURRENT WORK (#141647 / PR #141842) — please don't close as a dup
There is concurrent activity in gh-141647 / PR gh-141842 touching the comparison dunders, but it is orthogonal: that PR's rewritten _BaseAddress.__lt__ stays scope-blind (return self._ip < other._ip) and adds no IPv6Address override, and its test_mixed_type_ordering skips same-type pairs, so this same-type scoped trichotomy failure survives that PR untested. This fix adds a scope-aware override on the IPv6Address subclass only and does not modify _BaseAddress.__lt__, so it composes cleanly regardless of merge order (or could be folded into #141842).
CPython versions tested on:
CPython main branch
Operating systems tested on:
Linux
Linked PRs
- gh-151772
- gh-151864
- gh-152320
Beitragsleitfaden
Erste Schritte
- Lies das ganze Issue und danach den Beitragsleitfaden des Projekts.
- Schreib ins Issue, dass du es übernimmst — das erspart doppelte Arbeit.
- Forke das Repository und arbeite in einem Branch.
- Öffne einen Pull Request, der die Issue-Nummer nennt.
Rechercherichtung
Beginnen Sie in Lib/ipaddress.py mit den Vergleichsmethoden von IPv6Address und reproduzieren Sie die Beispiele für scoped addresses aus dem Issue. Bestätigen Sie, dass die Sortierung für scoped addresses deterministisch und konsistent ist, während die Vergleiche von IPv4Address sowie die zugehörigen Vergleiche von IPv6Interface und IPv6Network unverändert bleiben.
Vom Indexierungsmodell aus dem Issue-Text verfasst.
Bewertung
- Tech-Stack
- python
- Bereich
- networking
- Issue-Typ
- Bug
- Schwierigkeit
- 3/5
- Geschätzter Aufwand
- 1-2 Tage
- Aktivitätsstatus
- Veraltet
- Klarheit
- Klar beschrieben
- Anfängerfreundlichkeit
- 35/100