Skip to content

#2313: Fixed python installation failing - #2330

Open
samuelkos17 wants to merge 11 commits into
devonfw:mainfrom
samuelkos17:feature/2313-python-installation-fails-with-wired-behaviour
Open

#2313: Fixed python installation failing#2330
samuelkos17 wants to merge 11 commits into
devonfw:mainfrom
samuelkos17:feature/2313-python-installation-fails-with-wired-behaviour

Conversation

@samuelkos17

@samuelkos17 samuelkos17 commented Aug 13, 2026

Copy link
Copy Markdown
Contributor

This PR fixes #2313

Implemented changes:

  • CVE Version Suggestion Bug:
    • Root Cause: In ToolCommandlet.cveCheck(), when a safer version above resolvedVersion was found and assigned to latest, nearest was reset to null but nearestVulnerabilities was left stale. This caused subsequent versions with anequal vulnerability profile to incorrectly claim the nearest slot via a flawed else if branch that compared against outdated CVE data.
    • Fix:
      • Reset nearestVulnerabilities = latestVulnerabilities whenever nearest is reset to null to prevent stale comparisons.
      • Corrected the nearest assignment condition from version.isGreater(resolvedVersion) to !version.isGreater(resolvedVersion) (nearest should only track versions below resolvedVersion, not above it).
  • Python Installation .venv Conflict (found while reproducing the bug from Python installation fails with wired behaviour #2313):
    • Root Cause: When installing a new Python version, uv venv --python creates a .venv directory in the software folder before it gets renamed to the target python/ folder. If a previous installation or interrupted install left a stale .venv directory behind, uv venv would fail with "A virtual environment already exists", because only the python/ target was backed up, not the intermediate .venv.
    • Fix: Added a check in Python.performToolInstallation() to delete any existing .venv directory before invoking uv venv.

Testing instructions

Please add conscise, understandable instructions on how a reviewer can test/verify the functionality of your contribution here:

  1. Checkout to this branch, run build-local-dev.sh and run ide install python 3.14.0.
  2. Two options 3.14.0 and 3.14.7 should be printed. Select 3.14.0.
  3. Python should be successfully installed.

Checklist for this PR

Make sure everything is checked before merging this PR. For further info please also see
our DoD.

  • When running mvn clean test locally all tests pass and build is successful
  • PR title is of the form #«issue-id»: «brief summary» (e.g. #921: fixed setup.bat and not feature/921 fixed setup.bat). If no issue ID exists, title only.
  • PR top-level comment summaries what has been done and contains link to addressed issue(s)
  • PR and issue(s) have suitable labels
  • Issue is set to In Progress and assigned to you or there is no issue (might happen for very small PRs)
  • You followed all coding conventions
  • You have added the issue implemented by your PR in CHANGELOG.adoc unless issue is labelled
    with internal
  • You have not changed any dependency in pom.xml files or otherwise if runtime dependencies changed, you have updated our LICENSE.asciidoc
  • You have formulated clear instructions on how to test your contribution under "Testing instructions"

@github-project-automation github-project-automation Bot moved this to 🆕 New in IDEasy board Aug 13, 2026
@samuelkos17 samuelkos17 self-assigned this Aug 13, 2026
@samuelkos17 samuelkos17 added python runtime for python language install installation process of IDE + tools and install commandlet bugfix PR that fixes a bug issue uv fast Python package and project manager labels Aug 13, 2026
@samuelkos17 samuelkos17 moved this from 🆕 New to Team Review in IDEasy board Aug 13, 2026
@coveralls

coveralls commented Aug 13, 2026

Copy link
Copy Markdown
Collaborator

Coverage Report for CI Build 32126869284

Coverage decreased (-0.007%) to 72.901%

Details

  • Coverage decreased (-0.007%) from the base build.
  • Patch coverage: No coverable lines changed in this PR.
  • 34 coverage regressions across 3 files.

Uncovered Changes

No uncovered changes found.

Coverage Regressions

34 previously-covered lines in 3 files lost coverage.

File Lines Losing Coverage Coverage
com/devonfw/tools/ide/tool/ToolCommandlet.java 26 74.55%
com/devonfw/tools/ide/tool/python/Python.java 7 76.19%
com/devonfw/tools/ide/version/VersionSegment.java 1 90.03%

Coverage Stats

Coverage Status
Relevant Lines: 17559
Covered Lines: 13351
Line Coverage: 76.04%
Relevant Branches: 7763
Covered Branches: 5109
Branch Coverage: 65.81%
Branches in Coverage %: Yes
Coverage Strength: 3.23 hits per line

💛 - Coveralls

@maybeec maybeec 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.

Thanks for digging into #2313, and especially for tracking down the stale .venv while reproducing it 👍 The root-cause write-up in the PR description made this easy to follow, and the stale nearestVulnerabilities you found is a real defect.

I checked out the branch and compared the CVE suggestion behaviour against main by running CveCheckInstallTest on the existing intellij fixture with different configured versions. Unfortunately the change to the nearest condition regresses behaviour that is explicitly documented in documentation/security.adoc, so I have to request changes here.

Blocker

  • ToolCommandlet.java:751!version.isGreater(resolvedVersion) removes the "nearest safe upgrade" suggestion. documentation/security.adoc documents ide install mvn 3.6.2 offering Option 2: nearest (3.8.1 - safe), and 3.8.1 is greater than the requested 3.6.2. Reproduced below in the inline comment.

Should-fix

  • ToolCommandlet.java:745 — resetting nearestVulnerabilities to latestVulnerabilities raises the bar for nearest from "less CVEs than current" (as documented) to "as safe as latest", so partially-safer versions are no longer suggested once a fully safe latest exists. Inline comment contains an alternative that fixes the reported problem without either side effect, verified against the existing tests.
  • No regression test. Per AGENTS.md / DoD a bug fix starts with a failing test. Both fixes are testable with what is already there:
    • CVE logic: CveCheckInstallTest + the intellij fixture already contains safe and unsafe versions above and below the configured one; a second test project with a different INTELLIJ_VERSION is enough to pin the nearest semantics (that is exactly how I reproduced the regression).
    • .venv cleanup: PythonTest.testInstallOnIntelMacResolvesVersionFromUvNotIdeUrls shows the uv interaction is mockable, so a test that pre-creates software/.venv and asserts the install succeeds (and the folder is gone) is feasible.
  • CHANGELOG.adoc entry missing (the checkbox is unticked in the PR description). Both defects shipped in released versions — CVE suggestions since #1145, so this is user-facing and needs an entry under == 2026.08.001, unless the issue gets the internal label.
  • Python.java:57 — redundant Files.exists guard, see inline comment.
  • Python.java:56".venv" is now a literal in two places in this class; coding-conventions.adoc § Constants asks for a static final constant.
  • Scope vs. the issue. #2313 reproduces with ide python install 3.14.0 (which runs the python binary with the arguments install 3.14.0 — that is what the can't open file '...\software\install' in the issue log comes from), while the testing instructions here use ide install python 3.14.0. Please confirm what the reporter's exact command does after this PR, or state in the issue that the command was mistyped and which part of the reported behaviour is actually fixed.
  • Manual QA. The uv-driven python installation is not exercised end-to-end in CI, so please verify the stale-.venv scenario manually (interrupt an install, then re-install) on Windows and at least one Unix OS before merging.

Housekeeping

  • The branch is BEHIND main — please update it before merging.
  • Neither the PR nor issue #2313 has a milestone set.
  • Non-blocking, pre-existing and outside the diff: Python.java:31 declares private final VersionIdentifier PYTHON_MIN_VERSION — a constant name on a non-static field initialized at its declaration (coding-conventions.adoc § Constants and § Field Initialization). Nice to clean up while you are in this file.

Comment thread cli/src/main/java/com/devonfw/tools/ide/tool/ToolCommandlet.java Outdated
Comment thread cli/src/main/java/com/devonfw/tools/ide/tool/ToolCommandlet.java Outdated
Comment thread cli/src/main/java/com/devonfw/tools/ide/tool/python/Python.java Outdated
Comment thread cli/src/main/java/com/devonfw/tools/ide/tool/python/Python.java Outdated
@samuelkos17 samuelkos17 added this to the release:2026.08.002 milestone Aug 14, 2026
@samuelkos17
samuelkos17 force-pushed the feature/2313-python-installation-fails-with-wired-behaviour branch from 3c2ea29 to 77e3cb0 Compare August 14, 2026 06:49
@samuelkos17
samuelkos17 requested a review from maybeec August 14, 2026 06:50
@samuelkos17

Copy link
Copy Markdown
Contributor Author

@maybeec thanks for the Review! You were totally right with the problem of the nearest version. I've implemented your suggestion and added the changelog entry.

@maybeec maybeec 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.

Thanks for turning this around so quickly, and for taking the alternative from the last round seriously. I re-checked out the branch and re-ran the tests: the CVE behaviour is correct again - INTELLIJ_VERSION=2022.3 offers nearest (2022.3.2 - safe) as documented in documentation/security.adoc, and the new post-loop guard does suppress the useless suggestion from #2313. CHANGELOG.adoc, the milestone and the merge with main are all sorted now.

One correction on my side: I wrote == 2026.08.001 for the changelog entry last time. The milestone is release:2026.08.002, so where you put it is the right place.

Status of the previous review

Addressed:

  • Blocker ToolCommandlet.java:751 - the ! inversion is effectively reverted, the "nearest safe upgrade" suggestion is back.
  • Should-fix ToolCommandlet.java:745 - nearestVulnerabilities reset reverted, post-loop guard adopted.
  • Should-fix Python.java - redundant Files.exists guard removed, .venv literal extracted into VENV_FOLDER.
  • Should-fix CHANGELOG.adoc entry added (please also tick the checkbox in the PR description).
  • Housekeeping - branch merged with main (MERGEABLE/CLEAN), milestone set on both PR and issue.

Still open - details below.

Blocker

  • Out-commented code in ToolCommandlet.java (lines 745 and 751). Both reverts were done by commenting out rather than deleting. documentation/contributing/coding-conventions.adoc (Clean Code section) states explicitly: "Do not push out-commented code". The /*!*/ on line 751 is the worse of the two - a disabled operator sitting inside a live boolean expression is one careless edit away from silently reintroducing exactly the regression we just removed, and it hides from the next reader that this line is the load-bearing part of the documented nearest semantics. Please delete both; git history is what keeps the old variant.

Should-fix

  • Still no regression test. This was the main open item last round and it is unchanged: the diff touches no test at all. Per AGENTS.md and documentation/contributing/DoD.adoc a bug fix starts with a failing test - otherwise nothing stops the next refactoring of cveCheck() from reintroducing either defect, which is exactly how we got here. I did the work to show it is cheap; the proposal below is verified, not hypothetical.

  • Scope vs. issue #2313. Unchanged: the issue reproduces with ide python install 3.14.0 (which runs the python binary with the arguments install 3.14.0 - that is where can't open file '...\software\install' in the reported log comes from), while the testing instructions here use ide install python 3.14.0. There is still no comment on the issue clarifying this. Please either confirm what the reporter's exact command does after this PR, or note on the issue that the command was mistyped and which part of the reported behaviour is actually fixed - otherwise we close #2313 without knowing whether the reporter's symptom is gone.

  • Manual QA. Unchanged: the uv-driven python installation is not exercised end-to-end in CI. Please confirm in the PR that you interrupted an install and re-installed successfully on Windows and at least one Unix OS.

Change proposal (verified locally)

I wrote the three missing tests and validated each one both ways - every test below fails without the corresponding production change and passes with it. Verified on this branch on Windows via mvn -Dtest=CveCheckInstallTest test and mvn -Dtest=PythonTest test.

Two notes that cost me some time and will save you the same:

  1. newContext(...) already resolves the variables, so writing settings/ide.properties afterwards has no effect unless you call context.reload().
  2. The shared intellij CVE fixture cannot reproduce the #2313 end state: every version below the configured one is safer, so a legitimate nearest always overwrites the bogus one. Copying src/test/resources/urls into the project's target folder and rewriting security.json there keeps the git-tracked fixture untouched (junit-testing.adoc: never write into src/...) and makes the defect reproducible.

cli/src/test/java/com/devonfw/tools/ide/tool/CveCheckInstallTest.java:

 import com.devonfw.tools.ide.context.AbstractIdeContextTest;
 import com.devonfw.tools.ide.context.IdeTestContext;
+import com.devonfw.tools.ide.io.FileAccess;
+import com.devonfw.tools.ide.io.FileCopyMode;
 import com.devonfw.tools.ide.tool.intellij.Intellij;
 import com.devonfw.tools.ide.tool.repository.ToolRepository;
@@
   protected static final Path URLS_PATH = Path.of("src/test/resources/urls");
   private static final String PROJECT_INTELLIJ = "intellij";
+
+  private static final String SECURITY_JSON_EQUAL_SEVERITY = """
+      {
+        "issues": [
+          {
+            "id": "CVE-TEST-EQUAL",
+            "severity": 5.0,
+            "versions": [
+              "(0,2025.1.1)"
+            ]
+          },
+          {
+            "id": "CVE-TEST-HIGH",
+            "severity": 9.0,
+            "versions": [
+              "[2025.1.1]"
+            ]
+          }
+        ]
+      }
+      """;
   private final IdeTestContext context = newContext(PROJECT_INTELLIJ);
@@ (appended at the end of the class)
+  /**
+   * Install Intellij with a configured version for which a version above it is the nearest safe upgrade. Ensures the documented "nearest" suggestion (see
+   * {@code documentation/security.adoc}) also offers versions greater than the configured one.
+   */
+  @Test
+  void testInstallToolNearestSuggestsMinimalSafeUpgrade() {
+    //arrange
+    IdeTestContext context = newContext(PROJECT_INTELLIJ);
+    context.setUrlsPath(URLS_PATH);
+    context.getFileAccess().writeFileContent("JAVA_VERSION=17.0.10_7\nINTELLIJ_VERSION=2022.3\n", context.getSettingsPath().resolve("ide.properties"));
+    context.reload();
+    Intellij commandlet = new Intellij(context);
+    context.setAnswers("nearest");
+
+    //act
+    commandlet.install();
+
+    //assert
+    assertThat(context.getSoftwarePath().resolve("intellij").resolve(IdeTestContext.FILE_SOFTWARE_VERSION)).exists().hasContent("2022.3.2");
+  }
+
+  /**
+   * Install Intellij where the only allowed version above the configured one has exactly the same CVEs. Such a version must never be offered as "nearest"
+   * since it does not reduce the vulnerabilities - this is the bug reported in <a href="https://github.com/devonfw/IDEasy/issues/2313">#2313</a>.
+   */
+  @Test
+  void testInstallToolWithoutNearestIfNotSaferThanCurrent() {
+    //arrange
+    IdeTestContext context = newContext(PROJECT_INTELLIJ);
+    Path urlsPath = context.getIdeRoot().resolve("cve-urls");
+    FileAccess fileAccess = context.getFileAccess();
+    fileAccess.mkdirs(urlsPath);
+    fileAccess.copy(URLS_PATH, urlsPath, FileCopyMode.COPY_TREE_OVERRIDE_TREE);
+    fileAccess.writeFileContent(SECURITY_JSON_EQUAL_SEVERITY, urlsPath.resolve("urls").resolve("intellij").resolve("security.json"));
+    context.setUrlsPath(urlsPath.resolve("urls"));
+    Intellij commandlet = new Intellij(context);
+    context.setAnswers("current");
+
+    //act
+    commandlet.install();
+
+    //assert
+    assertThat(context).logAtInteraction().hasMessageContaining("latest (2025.1.1.1 - safe)");
+    assertThat(context).logAtInteraction().hasNoMessageContaining("nearest (");
+  }
  • testInstallToolNearestSuggestsMinimalSafeUpgrade pins the behaviour the first version of this PR broke. Against the original !version.isGreater(...) variant it errors out (no nearest option to answer); against the current branch it is green.
  • testInstallToolWithoutNearestIfNotSaferThanCurrent pins the actual #2313 fix. Against main it fails with Found unexpected log entry: Option 2: nearest (2024.2.6 - unsafe) - a suggestion with exactly the same max severity as the configured version, i.e. the "why is it asking about 3.14.7?" symptom. Against the current branch it is green.

cli/src/test/java/com/devonfw/tools/ide/tool/python/PythonTest.java:

+  /**
+   * Test that a stale {@code .venv} folder left behind by a previously interrupted installation is removed before {@code uv venv} is invoked, see
+   * <a href="https://github.com/devonfw/IDEasy/issues/2313">#2313</a>.
+   */
+  @Test
+  public void testInstallRemovesStaleVenvFolder(WireMockRuntimeInfo wireMockRuntimeInfo) {
+
+    // arrange
+    IdeTestContext context = newContext(PROJECT_UV, wireMockRuntimeInfo);
+    context.setSystemInfo(SystemInfoMock.MAC_X64);
+    Path staleMarker = context.getSoftwarePath().resolve(".venv").resolve("stale.txt");
+    context.getFileAccess().writeFileContent("stale", staleMarker, true);
+    Python python = context.getCommandletManager().getCommandlet(Python.class);
+
+    // act
+    python.install();
+
+    // assert
+    assertThat(context.getSoftwarePath().resolve("python").resolve("stale.txt")).doesNotExist();
+    assertThat(context.getSoftwarePath().resolve(".venv")).doesNotExist();
+    assertThat(context).logAtSuccess().hasMessageContaining("Successfully installed python");
+  }

The marker file is what makes this a real test rather than a tautology: without your fileAccess.delete(venvPath) the mocked uv venv populates the existing .venv, so the stale content is moved into software/python and stale.txt survives the install. Against main the test fails on exactly that; against the current branch it is green.

Feel free to adjust naming or fold the two CVE tests into one - the important part is that both defects are pinned. Note that staleMarker repeats the ".venv" literal, so you may want to make VENV_FOLDER package-private and reuse it in the test.

Minor (non-blocking)

  • Python.java:33 - VENV_FOLDER is a static constant declared after the instance field PYTHON_MIN_VERSION, and it has no JavaDoc. See inline comment.
  • Python.java:31 - pre-existing, mentioned last time and still open: private final VersionIdentifier PYTHON_MIN_VERSION is a constant name on a non-static field initialized at its declaration (coding-conventions.adoc, sections Constants and Field Initialization). Nice to clean up while you are in this file.
  • The CHANGELOG.adoc checkbox in the PR description is still unticked although the entry exists.

Comment thread cli/src/main/java/com/devonfw/tools/ide/tool/ToolCommandlet.java Outdated
Comment thread cli/src/main/java/com/devonfw/tools/ide/tool/ToolCommandlet.java Outdated
Comment thread cli/src/main/java/com/devonfw/tools/ide/tool/ToolCommandlet.java
Comment thread cli/src/main/java/com/devonfw/tools/ide/tool/python/Python.java Outdated
samuelkos17 and others added 6 commits August 18, 2026 08:19
Co-authored-by: Malte Brunnlieb <maybeec@users.noreply.github.com>
Co-authored-by: Malte Brunnlieb <maybeec@users.noreply.github.com>
Co-authored-by: Malte Brunnlieb <maybeec@users.noreply.github.com>
…-installation-fails-with-wired-behaviour' into feature/2313-python-installation-fails-with-wired-behaviour

# Conflicts:
#	cli/src/main/java/com/devonfw/tools/ide/tool/python/Python.java
@samuelkos17

Copy link
Copy Markdown
Contributor Author

Thanks for the Re-Review and the proposed tests. Regarding your questions:

This is the output now, when i run ide install python 3.14.0:
Option 1: current (3.14.0 - unsafe)
Option 2: nearest (3.14.6 - unsafe)
Option 3: latest (3.14.7 - unsafe)

I've also installed & uninstalled Python successfully on Windows and WSL.

@hohwille hohwille 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.

@samuelkos17 thanks for your PR. Great analysis, fix and test improvement 👍
@maybeec thanks for your excellent review support.
I left some minor suggestions to keep our code clean but then this is ready to merge.
Functionally all is already perfect and I also tested it and can confirm it fixes the bug.

Comment thread cli/src/main/java/com/devonfw/tools/ide/tool/python/Python.java Outdated
Comment thread cli/src/main/java/com/devonfw/tools/ide/tool/python/Python.java Outdated
Comment thread cli/src/main/java/com/devonfw/tools/ide/tool/python/Python.java Outdated
Comment on lines +59 to +62
Path venvPath = softwarePath.resolve(VENV_FOLDER);

fileAccess.delete(venvPath);

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.

Nothing wrong here. If I understand it correctly, uv.installPython might fail if the .venv folder was already present (e.g. from a previous incomplete setup that was aborted or failed).
Shouldn't this be considered as a bug of installPython method so it should be fixed there?
We can also keep it as is - I just want to understand and challenge this...

@samuelkos17 samuelkos17 Aug 18, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Yes, you understood that correctly. I've encountered this issue while reproducing the bug. And yeah you're right, since this specifically concerns Uv it should be understood as a bug of the installPython() method of Uv.java. However, moving the bugfix there would require a few more changes than if we just keep it this way, what do you say should I move it there or keep it here?

…make it static

Co-authored-by: Jörg Hohwiller <hohwille@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bugfix PR that fixes a bug issue install installation process of IDE + tools and install commandlet python runtime for python language uv fast Python package and project manager

Projects

Status: Team Review

Development

Successfully merging this pull request may close these issues.

Python installation fails with wired behaviour

4 participants