Skip to content

← Memory, Copies and Slow Code step 4 of 38

Easy Primitives

Fix a Version Class That Compares Strings with is

Version holds a release such as 2.0.0-beta. The number is major.minor.patch, and the text after the first hyphen is a label. The starter has two bugs:

  • is_prerelease compares the label with is, so it can miss a "beta" label that was read from input.
  • The label takes part in ==, ordering and the hash, so 2.0.0-beta and 2.0.0 count as two different releases.
solve(["2.0.0-beta", "1.9.9", "2.0.0"])

returns

{
    "sorted": ["1.9.9", "2.0.0"],
    "unique": 2,
    "prerelease": ["2.0.0-beta"],
    "eq_foreign": False,
    "hash_stable": True,
}

What to change

  • In is_prerelease, return whether the label is in PRERELEASE_LABELS, which holds exactly "alpha", "beta" and "rc". Compare by value, not with is. Matching is case-sensitive, so "Beta" does not count.
  • Declare label with field(default="", compare=False). A version's value is then only (major, minor, patch). Two versions with the same numbers are equal and have equal hashes, whatever their labels.

This model is simpler than Semantic Versioning, where 2.0.0-beta sorts before 2.0.0. Here they are the same release.

Keep parse, release and solve as they are. parse splits at the first hyphen and turns the three numbers into int, so 1.0.10 sorts after 1.0.2. With no hyphen, or nothing after it, the label is empty. Any later hyphens stay in the label. Every input is a valid version. Don't change specs.

What the driver reports

  • "sorted": the distinct releases in numeric order, as "major.minor.patch" without labels.
  • "unique": how many distinct releases there are.
  • "prerelease": the input strings whose label is a prerelease label, in input order, with repeats kept.
  • "eq_foreign": whether the first version equals a plain object(). It must be False, also for empty input.
  • "hash_stable": whether every pair of equal versions has equal hashes. It is True when there are no pairs.

Two different versions can have the same hash. A set still keeps both, because it also checks ==, and one test relies on that.

Empty input returns empty lists, 0 for "unique", False for "eq_foreign" and True for "hash_stable". Your code must pass mypy --strict.