Skip to content

maven.py: Version.__hash__ inconsistent with __eq__ due to _unparsed hash and non-recursive _normalize #189

@selsky

Description

@selsky

Two related bugs cause Version.__hash__ to violate the hash/eq contract:

  1. __hash__ uses hash(self._unparsed) but __eq__ compares via self._parsed.
    Semantically equal versions like "1" and "1.0" are == but have different hashes.

  2. _normalize doesn't recurse into nested sublists, so _parsed isn't fully
    canonical even if __hash__ is changed to use it. For example, "1-2-0" parses
    to (1, (2, ())) while "1-2" parses to (1, (2,)). These compare equal via
    __cmp__ (which handles the mismatch at comparison time) but are structurally
    different, so hash() differs.

Expected: a == b implies hash(a) == hash(b) (Python data model requirement).

Fix: Both bugs must be fixed together:

  1. Make _normalize recursive — normalize sublists before stripping trailing
    nulls from the parent — so that _parsed is truly canonical.
  2. Change __hash__ to return hash(self._parsed).

Reproduction:

from univers.maven import Version

# Bug 1: simple trailing null
a, b = Version("1"), Version("1.0")
assert a == b                # passes
assert hash(a) == hash(b)    # fails

# Bug 2: nested trailing null (still fails with just hash(_parsed))
a, b = Version("1-2-0"), Version("1-2")
assert a == b                # passes
assert hash(a) == hash(b)    # fails

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions