Skip to content

馃悰 fix(spec): treat unparsable version specifiers as literal paths - #157

Merged
gaborbernat merged 4 commits into
tox-dev:mainfrom
darrenhuai:fix/unparsable-specifier
Oct 27, 2026
Merged

gaborbernat merged 4 commits into
tox-dev:mainfrom
darrenhuai:fix/unparsable-specifier

Conversation

@darrenhuai

@darrenhuai darrenhuai commented Oct 22, 2026 •

Copy link
Copy Markdown
Contributor

get_interpreter([">=3.12 <4", sys.executable]) crashed with a bare AssertionError instead of moving on to the next key. 馃悰 Any version specifier whose version python-discovery can't read hit this assert: a missing comma (>=3.12 <4), >=3.x, or forms PEP 440 allows but this parser doesn't, such as >=3.10.post1. Users reach it through virtualenv -p or tox's base_python. Under python -O the assert disappears, and the same specs match nothing or raise AttributeError on a pre-release interpreter.

The specifier set never raises on bad input. It keeps an item with an unreadable version and silently drops an item without an operator. Spec parsing now accepts a specifier only when every comma-separated item parsed into a usable version, and otherwise treats the string as a literal executable path, the same fallback #147 gave python.. That rule also covers <,4, which used to parse to an empty set and match every interpreter, and >=3.12,foo or >=3.12, 4, which used to lose their second item and act as >=3.12. A PythonSpec built by hand can still carry an unreadable version, so the version check returns no match for it instead of asserting.

The explanation page now lists the version forms a specifier understands and what happens to anything else.

darrenhuai and others added 4 commits October 21, 2026 22:36
A version specifier whose version SimpleVersion cannot read, such as
`>=3.x`, `>=3.10.post1` or the missing-comma typo `>=3.12 <4`, made
get_interpreter and iter_interpreters fail with a bare AssertionError on
the first interpreter they checked, so later keys in a list were never
tried. SimpleSpecifierSet never raises: it stores an unparsable version
as None and drops items without an operator. The literal-path fallback
in _parse_specifier therefore never ran, and the None reached the
type-narrowing assert in PythonInfo._satisfies_version_specifier. Under
-O the assert is gone and the same specs quietly match nothing, and some
of them raise AttributeError on a prerelease interpreter.

_parse_specifier now falls back to a literal path when an item has no
parsed version or no item is left, the same way tox-dev#147 handles malformed
version specs. That also stops a spec like `<,4` from matching every
interpreter. The assert becomes a no-match check, as in
SimpleSpecifier.contains, so a PythonSpec built by hand with such a
specifier set no longer crashes either.
SimpleSpecifierSet drops items it cannot parse, so ">=3.12,foo" and
">=3.12, 4" were read as ">=3.12". Fall back to a literal path unless
every comma-separated item parsed, which also covers "<,4".
@gaborbernat gaborbernat added the bug Something isn't working label Oct 27, 2026
@gaborbernat gaborbernat changed the title fix(spec): treat unparsable version specifiers as literal paths 馃悰 fix(spec): treat unparsable version specifiers as literal paths Oct 27, 2026

@gaborbernat gaborbernat left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@gaborbernat
gaborbernat merged commit d323a51 into tox-dev:main Oct 27, 2026
21 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants