10aday › Version Constraint Checker › Poetry ^ and ~ to PEP 440
^ and ~ version constraints, and how to write them in PEP 440Short answer: in Poetry, ^1.2.3 means ≥1.2.3 <2.0.0: anything up to the next change of the left-most non-zero number. So ^0.2.3 means ≥0.2.3 <0.3.0.
~1.2.3 means ≥1.2.3 <1.3.0 (patch updates), but ~1 means <2. A bare 1.2.3 is an exact pin.
Neither ^ nor ~ exist in PEP 440, so the [project] table used by Poetry 2, uv, pip and Hatch rejects them. Write the bounds out: ^1.2.3 → >=1.2.3,<2.0.0.
Careful: ~=1.2.3 is not the same as ^1.2.3.
Migrating a whole file to Poetry 2 or uv? Paste your pyproject.toml into the Poetry to PEP 621 converter: it rewrites every dependency, the python constraint and the groups.
Have a constraint and a list of versions? Paste them into the Version Constraint Checker: it shows, side by side, what npm, Cargo, Composer, pip and RubyGems accept.
Middle column: the exact text to put in [project] dependencies, requirements.txt or uv add. It is what our converter outputs, and each range is checked with pip's rules.
Poetry ([tool.poetry]) | PEP 440 ([project], pip, uv) | Allows |
|---|---|---|
^1.2.3 | >=1.2.3,<2.0.0 | ≥1.2.3 <2.0.0 |
^1.2 | >=1.2,<2.0 | ≥1.2.0 <2.0.0 |
^1 | >=1,<2 | ≥1.0.0 <2.0.0 |
^0.2.3below 1.0, the minor is the breaking number | >=0.2.3,<0.3.0 | ≥0.2.3 <0.3.0 |
^0.0.3only 0.0.3 | >=0.0.3,<0.0.4 | ≥0.0.3 <0.0.4 |
^0 | >=0,<1 | ≥0.0.0 <1.0.0 |
~1.2.3 | >=1.2.3,<1.3.0 | ≥1.2.3 <1.3.0 |
~1.2 | >=1.2,<1.3 | ≥1.2.0 <1.3.0 |
~1one number: same as ^1 | >=1,<2 | ≥1.0.0 <2.0.0 |
~0.2.3 | >=0.2.3,<0.3.0 | ≥0.2.3 <0.3.0 |
~=1.2already PEP 440 | ~=1.2 | ≥1.2.0 <2.0.0 |
~=1Poetry accepts it, pip does not | >=1,<2 | ≥1.0.0 <2.0.0 |
1.2.* | ==1.2.* | ≥1.2.0 <1.3.0 |
* | "" (no specifier) | any version |
1.2.3bare version: exact pin (Cargo would read ^) | ==1.2.3 | exactly 1.2.3 |
>=1.2 <2.0space or comma = and | >=1.2,<2.0 | ≥1.2.0 <2.0.0 |
^1.2 || ^2.0 | >=1.2,<2.0 or >=2.0,<3.0no single PEP 440 form | ≥1.2.0 <2.0.0 or ≥2.0.0 <3.0.0 |
Ranges shown for final releases. Poetry and pip both skip pre-releases (2.0.0rc1) unless you ask for them, but their edge rules differ; the converter lists the cases it cannot translate exactly.
Both look like “compatible release”, so ^ is often rewritten as ~= with the same numbers. That is right for ^1.2 and ^0.2.3, wrong for ^1.2.3 and ^0.2:
| Poetry | Wrong translation | It allows | Should allow |
|---|---|---|---|
^1.2.3 | ~=1.2.3 | ≥1.2.3 <1.3.0 | ≥1.2.3 <2.0.0 |
^0.2 | ~=0.2 | ≥0.2.0 <1.0.0 | ≥0.2.0 <0.3.0 |
^1.2 | ~=1.2 (fine) | ≥1.2.0 <2.0.0 | ≥1.2.0 <2.0.0 |
^0.2.3 | ~=0.2.3 (fine) | ≥0.2.3 <0.3.0 | ≥0.2.3 <0.3.0 |
~=1.2.3 blocks the 1.3 minor release that ^1.2.3 allowed: you silently stop getting features and fixes.
~=0.2 lets 0.3 and later 0.x releases in, which ^0.2 excluded on purpose, since before 1.0 a minor bump may break the API.
[tool.poetry.dependencies] (Poetry 1 and 2): ^, ~, *, ||, a bare version, and PEP 440 operators.[project] dependencies (PEP 621: Poetry 2, uv, Hatch, PDM, setuptools): PEP 440 only. Poetry's documentation says caret and tilde are not supported there.requirements.txt, uv add: PEP 440 only. Same for the Python version: python = "^3.10" becomes requires-python = ">=3.10,<4.0", though many projects simply write ">=3.10".It is a caret requirement: updates that do not change the left-most non-zero number are allowed. ^1.2.3 = ≥1.2.3 <2.0.0, ^0.2.3 = ≥0.2.3 <0.3.0, ^0.0.3 = ≥0.0.3 <0.0.4. In PEP 440 you write >=1.2.3,<2.0.0.
A tilde requirement. With two or three numbers only the last one may increase, starting from the second: ~1.2.3 = ≥1.2.3 <1.3.0 and ~1.2 = ≥1.2 <1.3. With one number, ~1 = ≥1 <2.
No. ~=1.2.3 stops before 1.3.0; ^1.2.3 goes up to 2.0.0. The PEP 440 form of ^1.2.3 is >=1.2.3,<2.0.0. For ^1.2, ~=1.2 is equivalent.
No. Poetry 2 reads PEP 621 [project] metadata, where only PEP 440 specifiers are valid; ^ and ~ are only accepted in [tool.poetry.dependencies]. uv and pip reject them too.
You cannot in one specifier: PEP 440 has no “or”. Here the two ranges touch, so >=1.2,<3.0 is equivalent. When they do not touch, pick one range or split the dependency with environment markers.
^ and ~ into [project] dependencies (Poetry 2, uv)