When recently updating our project's requirements.txt file, which had dependencies locked to specific versions (like pydantic==2.6.0
), I found myself wanting to allow minor version updates without opening the door to potentially disruptive major version changes. Initially, I considered setting a version range, such as pydantic>=2.6.0,<3.0.0
which is how I always done it in the past. However, this approach felt clunky and I wondered if there was a better way.
After a bit of research, I stumbled upon a nifty feature called the compatible release clause, symbolized by the ~=
operator, followed by a version number. According to the official documentation, a compatible release clause aims to match any candidate version that is expected to be compatible with the specified version, effectively allowing updates within a safe boundary.
Here’s how it works: For a given release identifier V.N
, the compatible release clause is roughly equivalent to combining the following comparison clauses: >= V.N, == V.*
. This means:
~=2.6
would match versions>= 2.6
and==2.*
, allowing any version greater than or equal to 2.6 but less than 3.~= 2.6.0
matches versions>=2.6.0
and==2.6.*
, enabling any version greater than or equal to 2.6.0 but less than the next minor increment.
Note that the ~=
operator should not be used with a single-segment version number, such as ~=2
.
For the sake of completeness, other clauses for specifying versions include:
~=
: Compatible release clause==
: Version matching clause!=
: Version exclusion clause<=, >=
: Inclusive ordered comparison clause<, >
: Exclusive ordered comparison clause===
: Arbitrary equality clause
I found the compatible release clause to be an elegant solution for managing project dependencies safely and efficiently, keeping updates within a compatible range without the fear of inadvertently upgrading to a major version that could break compatibility.