Repository: pdm-project/pdm

Issue:
test_use_invalid_wrapper_python test fails
While packaging pdm 2.2.1 for openSUSE/Factory we have discovered failing test test_use_invalid_wrapper_python:

- [x] I have searched the issue tracker and believe that this is not a duplicate.

**Make sure you run commands with `-v` flag before pasting the output.**

## Steps to reproduce

Run the test suite:
```
[  198s] =================================== FAILURES ===================================
[  198s] _______________________ test_use_invalid_wrapper_python ________________________
[  198s] 
[  198s] project = <Project '/tmp/pytest-of-abuild/pytest-0/test_use_invalid_wrapper_pytho0'>
[  198s] 
[  198s]     @pytest.mark.skipif(os.name != "posix", reason="Run on POSIX platforms only")
[  198s]     def test_use_invalid_wrapper_python(project):
[  198s]         wrapper_script = """#!/bin/bash
[  198s]     echo hello
[  198s]     """
[  198s]         shim_path = project.root.joinpath("python_shim.sh")
[  198s]         shim_path.write_text(wrapper_script)
[  198s]         shim_path.chmod(0o755)
[  198s]         with pytest.raises(InvalidPyVersion):
[  198s] >           actions.do_use(project, shim_path.as_posix())
[  198s] 
[  198s] tests/cli/test_use.py:60: 
[  198s] _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
[  198s] /usr/lib/python3.8/site-packages/pdm/cli/actions.py:617: in do_use
[  198s]     matching_interpreters = list(filter(version_matcher, found_interpreters))
[  198s] /usr/lib/python3.8/site-packages/pdm/cli/actions.py:588: in version_matcher
[  198s]     str(py_version.version), True
[  198s] /usr/lib/python3.8/site-packages/pdm/models/python.py:48: in version
[  198s]     return self._py_ver.version
[  198s] /usr/lib/python3.8/site-packages/findpython/python.py:65: in version
[  198s]     self._version = self._get_version()
[  198s] /usr/lib/python3.8/site-packages/findpython/python.py:165: in _get_version
[  198s]     return Version(version)
[  198s] _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
[  198s] 
[  198s] self = <[AttributeError("'Version' object has no attribute '_version'") raised in repr()] Version object at 0x7ff1cd2fbd00>
[  198s] version = 'hello'
[  198s] 
[  198s]     def __init__(self, version: str) -> None:
[  198s]     
[  198s]         # Validate the version and parse it into pieces
[  198s]         match = self._regex.search(version)
[  198s]         if not match:
[  198s] >           raise InvalidVersion(f"Invalid version: '{version}'")
[  198s] E           packaging.version.InvalidVersion: Invalid version: 'hello'
[  198s] 
[  198s] /usr/lib/python3.8/site-packages/packaging/version.py:266: InvalidVersion
[  198s] ---------------------------- Captured stdout setup -----------------------------
[  198s] Changes are written to pyproject.toml.
[  198s] =============================== warnings summary ===============================
[  198s] tests/test_integration.py:31
[  198s]   /home/abuild/rpmbuild/BUILD/pdm-2.2.1/tests/test_integration.py:31: PytestUnknownMarkWarning: Unknown pytest.mark.flaky - is this a typo?  You can register custom marks to avoid this warning - for details, see https://docs.pytest.org/en/stable/how-to/mark.html
[  198s]     @pytest.mark.flaky(reruns=3)
[  198s] 
[  198s] -- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
[  198s] =========================== short test summary info ============================
[  198s] FAILED tests/cli/test_use.py::test_use_invalid_wrapper_python - packaging.ver...
[  198s] ===== 1 failed, 585 passed, 12 deselected, 1 warning in 184.12s (0:03:04) ======
```

## Actual behavior

Test fails

## Expected behavior

Whole test suite passes.

## Environment Information

```bash
# Paste the output of `pdm info && pdm info --env` below:

stitny/t/pdm-test$ pdm info
PDM version:
  2.2.1
Python Interpreter:
  /tmp/pdm-test/.venv/bin/python (3.10)
Project Root:
  /tmp/pdm-test
Project Packages:
  None
stitny/t/pdm-test$ pdm info --env
{
  "implementation_name": "cpython",
  "implementation_version": "3.10.8",
  "os_name": "posix",
  "platform_machine": "x86_64",
  "platform_release": "6.0.8-1-default",
  "platform_system": "Linux",
  "platform_version": "#1 SMP PREEMPT_DYNAMIC Fri Nov 11 08:02:50 UTC 2022 (1579d93)",
  "python_full_version": "3.10.8",
  "platform_python_implementation": "CPython",
  "python_version": "3.10",
  "sys_platform": "linux"
}
stitny/t/pdm-test$ 

```
Complete [build log](https://github.com/pdm-project/pdm/files/10015455/_log-test.txt) for version of packages used and steps taken.


Discussion:
codecov-commenter: # [Codecov](https://codecov.io/gh/pdm-project/pdm/pull/1518?src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=pdm-project) Report
Base: **85.30**% // Head: **85.30**% // No change to project coverage :thumbsup:
> Coverage data is based on head [(`f8ec8b7`)](https://codecov.io/gh/pdm-project/pdm/pull/1518?src=pr&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=pdm-project) compared to base [(`26f2a17`)](https://codecov.io/gh/pdm-project/pdm/commit/26f2a178e378442f9aaa7785a583f9f3c9e98a5b?el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=pdm-project).
> Patch coverage: 100.00% of modified lines in pull request are covered.

<details><summary>Additional details and impacted files</summary>


```diff
@@           Coverage Diff           @@
##             main    #1518   +/-   ##
=======================================
  Coverage   85.30%   85.30%           
=======================================
  Files          91       91           
  Lines        8000     8000           
  Branches     1898     1897    -1     
=======================================
  Hits         6824     6824           
  Misses        786      786           
  Partials      390      390           
```

| Flag | Coverage Δ | |
|---|---|---|
| unittests | `85.12% <100.00%> (ø)` | |

Flags with carried forward coverage won't be shown. [Click here](https://docs.codecov.io/docs/carryforward-flags?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=pdm-project#carryforward-flags-in-the-pull-request-comment) to find out more.

| [Impacted Files](https://codecov.io/gh/pdm-project/pdm/pull/1518?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=pdm-project) | Coverage Δ | |
|---|---|---|
| [src/pdm/cli/actions.py](https://codecov.io/gh/pdm-project/pdm/pull/1518/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=pdm-project#diff-c3JjL3BkbS9jbGkvYWN0aW9ucy5weQ==) | `78.50% <100.00%> (-0.16%)` | :arrow_down: |
| [src/pdm/models/python.py](https://codecov.io/gh/pdm-project/pdm/pull/1518/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=pdm-project#diff-c3JjL3BkbS9tb2RlbHMvcHl0aG9uLnB5) | `94.73% <100.00%> (+0.29%)` | :arrow_up: |

Help us with your feedback. Take ten seconds to tell us [how you rate us](https://about.codecov.io/nps?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=pdm-project). Have a feature suggestion? [Share it here.](https://app.codecov.io/gh/feedback/?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=pdm-project)

</details>

[:umbrella: View full report at Codecov](https://codecov.io/gh/pdm-project/pdm/pull/1518?src=pr&el=continue&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=pdm-project).   
:loudspeaker: Do you have feedback about the report comment? [Let us know in this issue](https://about.codecov.io/codecov-pr-comment-feedback/?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=pdm-project).


Patch:
diff --git a/news/1516.bugfix.md b/news/1516.bugfix.md
new file mode 100644
index 00000000..aeb4b7cb
--- /dev/null
+++ b/news/1516.bugfix.md
@@ -0,0 +1,1 @@
+Fix the test failure with the latest `findpython` installed.
diff --git a/pdm.lock b/pdm.lock
index 11487e8f..0e7aae6b 100644
--- a/pdm.lock
+++ b/pdm.lock
@@ -124,7 +124,7 @@ summary = "A platform independent file lock."
 
 [[package]]
 name = "findpython"
-version = "0.2.0"
+version = "0.2.2"
 requires_python = ">=3.7"
 summary = "A utility to find python versions on your system"
 dependencies = [
@@ -783,9 +783,9 @@ content_hash = "sha256:8254688e0619bf5e694bcd7ac7033d800b93c1764234994273a0bc459
     {url = "https://files.pythonhosted.org/packages/a6/d5/17f02b379525d1ff9678bfa58eb9548f561c8826deb0b85797aa0eed582d/filelock-3.7.1-py3-none-any.whl", hash = "sha256:37def7b658813cda163b56fc564cdc75e86d338246458c4c28ae84cabefa2404"},
     {url = "https://files.pythonhosted.org/packages/f3/c7/5c1aef87f1197d2134a096c0264890969213c9cbfb8a4102087e8d758b5c/filelock-3.7.1.tar.gz", hash = "sha256:3a0fd85166ad9dbab54c9aec96737b744106dc5f15c0b09a6744a445299fcf04"},
 ]
-"findpython 0.2.0" = [
-    {url = "https://files.pythonhosted.org/packages/17/16/7e7e7f6ae157e903c3285533f5d52f34fa8f25c8f4745699294b154e83fc/findpython-0.2.0.tar.gz", hash = "sha256:c2099ee0b71fc2714b64f68fd1f40bc0ee47f49dfe9547fb64d7cbcc02fe0871"},
-    {url = "https://files.pythonhosted.org/packages/6f/a5/538cce025f4eae09f138c4fcab5eb3c8fe4584006b0c9759e2554a274efc/findpython-0.2.0-py3-none-any.whl", hash = "sha256:110ec222a43aca3fcd154fd90b911f465c70e86787ae0532bab2266a95870fc9"},
+"findpython 0.2.2" = [
+    {url = "https://files.pythonhosted.org/packages/19/b4/6c35b7e741c18fb6d5be35e2d9099dc1a05a8525b45ebbb6985d101f2b62/findpython-0.2.2-py3-none-any.whl", hash = "sha256:62717187e728c3d38b2754dfd7e6b5cfa503ed3608b9ad93cb80dbf2497e92e0"},
+    {url = "https://files.pythonhosted.org/packages/28/96/ec16612c4384cfca9381239d06e9285ca41d749d4a5003df73e3a96255e7/findpython-0.2.2.tar.gz", hash = "sha256:80557961c04cf1c8c4ba4ca3ac7cf76ec27fa92788a6af42cb701e3450c49430"},
 ]
 "ghp-import 2.1.0" = [
     {url = "https://files.pythonhosted.org/packages/d9/29/d40217cbe2f6b1359e00c6c307bb3fc876ba74068cbab3dde77f03ca0dc4/ghp-import-2.1.0.tar.gz", hash = "sha256:9c535c4c61193c2df8871222567d7fd7e5014d835f97dc7b7439069e2413d343"},
diff --git a/src/pdm/cli/actions.py b/src/pdm/cli/actions.py
index 3be0a325..0e7f0b09 100644
--- a/src/pdm/cli/actions.py
+++ b/src/pdm/cli/actions.py
@@ -31,12 +31,7 @@ from pdm.cli.utils import (
     set_env_in_reg,
     translate_groups,
 )
-from pdm.exceptions import (
-    InvalidPyVersion,
-    NoPythonVersion,
-    PdmUsageError,
-    ProjectError,
-)
+from pdm.exceptions import NoPythonVersion, PdmUsageError, ProjectError
 from pdm.formats import FORMATS
 from pdm.formats.base import array_of_inline_tables, make_array, make_inline_table
 from pdm.models.backends import BuildBackend
@@ -579,8 +574,10 @@ def do_use(
         python = python.strip()
 
     def version_matcher(py_version: PythonInfo) -> bool:
-        return ignore_requires_python or project.python_requires.contains(
-            str(py_version.version), True
+        return (
+            ignore_requires_python
+            or py_version.valid
+            and project.python_requires.contains(str(py_version.version), True)
         )
 
     if not project.cache_dir.exists():
@@ -642,9 +639,6 @@ def do_use(
         if python:
             use_cache.set(python, selected_python.path.as_posix())
 
-    if not selected_python.valid:
-        path = str(selected_python.path)
-        raise InvalidPyVersion(f"Invalid Python interpreter: {path}")
     if not save:
         return selected_python
     old_python = (
diff --git a/src/pdm/models/python.py b/src/pdm/models/python.py
index 33802b72..e15146b6 100644
--- a/src/pdm/models/python.py
+++ b/src/pdm/models/python.py
@@ -5,7 +5,7 @@ from pathlib import Path
 from typing import Any
 
 from findpython import PythonVersion
-from packaging.version import Version
+from packaging.version import InvalidVersion, Version
 
 from pdm.compat import cached_property
 
@@ -72,6 +72,9 @@ class PythonInfo:
 
     @property
     def identifier(self) -> str:
-        if os.name == "nt" and self.is_32bit:
-            return f"{self.major}.{self.minor}-32"
-        return f"{self.major}.{self.minor}"
+        try:
+            if os.name == "nt" and self.is_32bit:
+                return f"{self.major}.{self.minor}-32"
+            return f"{self.major}.{self.minor}"
+        except InvalidVersion:
+            return "unknown"


Test patch:
diff --git a/tests/cli/test_use.py b/tests/cli/test_use.py
index ca1c5731..e65cac76 100644
--- a/tests/cli/test_use.py
+++ b/tests/cli/test_use.py
@@ -6,7 +6,7 @@ from pathlib import Path
 import pytest
 
 from pdm.cli import actions
-from pdm.exceptions import InvalidPyVersion
+from pdm.exceptions import NoPythonVersion
 from pdm.models.caches import JSONFileCache
 
 
@@ -54,7 +54,7 @@ echo hello
     shim_path = project.root.joinpath("python_shim.sh")
     shim_path.write_text(wrapper_script)
     shim_path.chmod(0o755)
-    with pytest.raises(InvalidPyVersion):
+    with pytest.raises(NoPythonVersion):
         actions.do_use(project, shim_path.as_posix())