We can't find the internet
Attempting to reconnect
Something went wrong!
Attempting to reconnect
← Modules, Packaging and Tooling step 28 of 41
Medium
Primitives
Check a Version Against a Specifier
Write the check an installer makes before it picks a release. Given a version
and a specifier, return True when the version satisfies every clause.
satisfies("1.10", ">1.9") # True, 10 is greater than 9
satisfies("1.0", "==1.0.0") # True, missing segments count as zero
satisfies("1.5.0", "~=1.4.2") # False, the prefix 1.4 does not match
satisfies("1.5", ">=1.0, <1.5") # False, the second clause fails
The starter compares versions as strings and ignores ~=, so it gets the
first three wrong.
Input format
- A version is one or more non-negative whole numbers joined by dots, such
as
"1.4.2". - A specifier is one or more clauses separated by commas, such as
">=1.2, <2". A clause is an operator followed by a release. - Ignore whitespace around the version, around each clause, and between an operator and its release.
- Support the operators
==,!=,>=,<=,>,<and~=. The inputs use no other syntax. There are no wildcards such as==1.4.*, and no prereleases, post-releases, development releases, epochs or local versions.
Comparison rules
- Compare releases one segment at a time, as numbers. Pad the shorter one
with zeros first, so
1.10 > 1.9and1.0 == 1.0.0. ~=Vneeds two things. The version must be at leastV, and it must start with the prefix you get by droppingV's last segment. Pad with zeros for the prefix too, so1satisfies~=1.0.0. For example,~=1.4.2accepts1.4.9and rejects1.5.0, and~=1.4accepts both.- Return
Trueonly when every clause matches. - A
~=clause needs at least two segments. RaiseValueErrorfor~=1. Parse and check every clause before you match any of them, sosatisfies("2", "<1, ~=1")raises instead of returningFalseat the first clause.
How to structure it
- Parse each clause into a frozen dataclass with two fields.
operatorhas the typeLiteral["==", "!=", ">=", "<=", "~=", ">", "<"], andreleasehas the typetuple[int, ...]. - Choose the comparison with
matchon the operator, and end withcase unreachable: assert_never(unreachable). If someone later adds an operator to theLiteraland forgets its branch, mypy reports an error. At runtime,assert_neveronly raisesAssertionErrorif a value reaches it. Your parser is what turns text into a valid operator. - Your code must pass
mypy --strict.
Your code, saved here
Sign in to access your accepted solutions and saved draft history. You can keep reading the lesson without an account.
Sign in to your accountStuck?
Python reference solution
Sign in to track your attempts toward unlocking the reference solution.