• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

devonfw / IDEasy / 22315552991

23 Feb 2026 04:40PM UTC coverage: 70.563% (+0.09%) from 70.474%
22315552991

Pull #1714

github

web-flow
Merge 7d88da975 into 379acdc9d
Pull Request #1714: #404: #1713: advanced logging

4081 of 6382 branches covered (63.95%)

Branch coverage included in aggregate %.

10644 of 14486 relevant lines covered (73.48%)

3.09 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

75.68
cli/src/main/java/com/devonfw/tools/ide/tool/python/Python.java
1
package com.devonfw.tools.ide.tool.python;
2

3
import java.nio.file.Files;
4
import java.nio.file.Path;
5
import java.nio.file.StandardCopyOption;
6
import java.util.Set;
7

8
import org.slf4j.Logger;
9
import org.slf4j.LoggerFactory;
10

11
import com.devonfw.tools.ide.cli.CliException;
12
import com.devonfw.tools.ide.common.Tag;
13
import com.devonfw.tools.ide.context.IdeContext;
14
import com.devonfw.tools.ide.io.FileAccess;
15
import com.devonfw.tools.ide.process.EnvironmentContext;
16
import com.devonfw.tools.ide.tool.LocalToolCommandlet;
17
import com.devonfw.tools.ide.tool.ToolCommandlet;
18
import com.devonfw.tools.ide.tool.ToolInstallRequest;
19
import com.devonfw.tools.ide.tool.ToolInstallation;
20
import com.devonfw.tools.ide.tool.uv.Uv;
21
import com.devonfw.tools.ide.version.VersionIdentifier;
22

23
/**
24
 * {@link ToolCommandlet} for <a href="https://www.python.org/">python</a>.
25
 */
26
public class Python extends LocalToolCommandlet {
27

28
  private static final Logger LOG = LoggerFactory.getLogger(Python.class);
4✔
29

30
  private final VersionIdentifier PYTHON_MIN_VERSION = VersionIdentifier.of("3.8.2");
4✔
31

32
  /**
33
   * The constructor.
34
   *
35
   * @param context the {@link IdeContext}.
36
   */
37
  public Python(IdeContext context) {
38

39
    super(context, "python", Set.of(Tag.PYTHON));
6✔
40
  }
1✔
41

42
  @Override
43
  protected void performToolInstallation(ToolInstallRequest request, Path installationPath) {
44

45
    VersionIdentifier resolvedVersion = request.getRequested().getResolvedVersion();
4✔
46
    if (resolvedVersion.compareVersion(PYTHON_MIN_VERSION).isLess()) {
6!
47
      throw new CliException("Python version must be at least " + this.PYTHON_MIN_VERSION);
×
48
    }
49

50
    FileAccess fileAccess = this.context.getFileAccess();
4✔
51
    if (Files.exists(installationPath)) {
5!
52
      fileAccess.backup(installationPath);
×
53
    }
54
    Path softwarePath = installationPath.getParent();
3✔
55
    Uv uv = this.context.getCommandletManager().getCommandlet(Uv.class);
7✔
56

57
    uv.installPython(softwarePath, resolvedVersion, request.getProcessContext());
6✔
58
    renameVenvFolderToPython(fileAccess, softwarePath, installationPath);
5✔
59
    this.context.writeVersionFile(resolvedVersion, installationPath);
5✔
60
    createWindowsSymlinkBinFolder(fileAccess, installationPath);
4✔
61
    LOG.debug("Installed {} in version {} at {}", this.tool, resolvedVersion, installationPath);
18✔
62
  }
1✔
63

64
  @Override
65
  public void setEnvironment(EnvironmentContext environmentContext, ToolInstallation toolInstallation, boolean additionalInstallation) {
66

67
    super.setEnvironment(environmentContext, toolInstallation, additionalInstallation);
5✔
68
    environmentContext.withEnvVar("VIRTUAL_ENV", toolInstallation.rootDir().toString());
7✔
69
  }
1✔
70

71
  @Override
72
  protected boolean isIgnoreSoftwareRepo() {
73

74
    return true;
2✔
75
  }
76

77
  /**
78
   * Creates a symlink from the "Scripts" folder to the "bin" folder on Windows systems. This is necessary for compatibility with tools that expect a "bin"
79
   * directory.
80
   *
81
   * @param fileAccess the {@link FileAccess} utility for file operations.
82
   * @param installationPath the path where Python is installed.
83
   */
84
  private void createWindowsSymlinkBinFolder(FileAccess fileAccess, Path installationPath) {
85

86
    if (!this.context.getSystemInfo().isWindows()) {
5!
87
      return;
1✔
88
    }
89
    Path scriptsPath = installationPath.resolve("Scripts");
×
90
    Path binPath = installationPath.resolve("bin");
×
91
    fileAccess.symlink(scriptsPath, binPath);
×
92
  }
×
93

94
  /**
95
   * Renames the ".venv" folder into the installation path (Python).
96
   *
97
   * @param fileAccess the {@link FileAccess} utility for file operations.
98
   * @param softwarePath the path where the software is installed.
99
   * @param installationPath the target path where the ".venv" folder should be moved.
100
   */
101
  private void renameVenvFolderToPython(FileAccess fileAccess, Path softwarePath, Path installationPath) {
102

103
    Path venvPath = softwarePath.resolve(".venv");
4✔
104
    fileAccess.move(venvPath, installationPath, StandardCopyOption.REPLACE_EXISTING);
10✔
105
  }
1✔
106

107
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc