@@ -1483,8 +1483,8 @@ impl PythonRequest {
14831483 /// - On Windows only, this allows `pythonw` as an alias for `python`.
14841484 /// - This allows `python` by itself (and on Windows, `pythonw`) as an alias for `default`.
14851485 ///
1486- /// This only returns `Err` if `@` is used, and the prefix is a match, but the version is
1487- /// invalid. Otherwise, if no match is found, it returns `Ok(None)`.
1486+ /// This can only return `Err` if `@` is used, see try_parse_tool_executable. Otherwise, if no
1487+ /// match is found, it returns `Ok(None)`.
14881488 pub fn try_parse_tool_executable ( value : & str ) -> Result < Option < PythonRequest > , Error > {
14891489 let lowercase_value = & value. to_ascii_lowercase ( ) ;
14901490 // Omitting the empty string from these lists excludes bare versions like "39".
@@ -1504,14 +1504,14 @@ impl PythonRequest {
15041504 )
15051505 }
15061506
1507- // This only returns Err() if @ is used, and the prefix is a match, but the version is invalid.
1508- // Otherwise, if no match is found, it returns Ok(None).
1507+ // This can only return Err() if @ is used, see try_split_prefix_and_version below. Otherwise,
1508+ // if no match is found, it returns Ok(None).
15091509 fn parse_versions_and_implementations < ' a > (
15101510 // typically "python", possibly also "pythonw" or "" (for bare versions)
15111511 abstract_version_prefixes : impl IntoIterator < Item = & ' a str > ,
15121512 // expected to be either long_names() or all names
15131513 implementation_names : impl IntoIterator < Item = & ' a str > ,
1514- // the string to parse, case-insensitive
1514+ // the string to parse
15151515 lowercase_value : & str ,
15161516 ) -> Result < Option < PythonRequest > , Error > {
15171517 for prefix in abstract_version_prefixes {
@@ -1546,11 +1546,16 @@ impl PythonRequest {
15461546 Ok ( None )
15471547 }
15481548
1549- // This only returns Err() if @ is used, and the prefix is a match, but the version is invalid.
1549+ // This can only returns Err() if @ is used. There are two error cases:
1550+ // - The value starts with @ (e.g. `@3.11`).
1551+ // - The prefix is a match, but the version is invalid (e.g. `[email protected] `). 15501552 fn try_split_prefix_and_version (
15511553 prefix : & str ,
15521554 lowercase_value : & str ,
15531555 ) -> Result < Option < VersionRequest > , Error > {
1556+ if lowercase_value. starts_with ( '@' ) {
1557+ return Err ( Error :: InvalidVersionRequest ( lowercase_value. to_string ( ) ) ) ;
1558+ }
15541559 let Some ( rest) = lowercase_value. strip_prefix ( prefix) else {
15551560 return Ok ( None ) ;
15561561 } ;
@@ -3428,5 +3433,7 @@ mod tests {
34283433 assert ! (
34293434 PythonRequest :: try_split_prefix_and_version( "prefix" , "prefix@3notaversion" ) . is_err( )
34303435 ) ;
3436+ // @ is not allowed if the prefix is empty.
3437+ assert ! ( PythonRequest :: try_split_prefix_and_version( "" , "@3" ) . is_err( ) ) ;
34313438 }
34323439}
0 commit comments