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

devonfw / IDEasy / 17759244918

16 Sep 2025 08:12AM UTC coverage: 68.69% (+0.1%) from 68.56%
17759244918

push

github

web-flow
#1454: added NpmBasedCommandlet, refactored/simplified installation (#1488)

3420 of 5441 branches covered (62.86%)

Branch coverage included in aggregate %.

8905 of 12502 relevant lines covered (71.23%)

3.13 hits per line

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

8.57
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 com.devonfw.tools.ide.cli.CliException;
9
import com.devonfw.tools.ide.common.Tag;
10
import com.devonfw.tools.ide.context.IdeContext;
11
import com.devonfw.tools.ide.io.FileAccess;
12
import com.devonfw.tools.ide.process.EnvironmentContext;
13
import com.devonfw.tools.ide.process.ProcessContext;
14
import com.devonfw.tools.ide.tool.LocalToolCommandlet;
15
import com.devonfw.tools.ide.tool.ToolCommandlet;
16
import com.devonfw.tools.ide.tool.ToolInstallation;
17
import com.devonfw.tools.ide.tool.repository.ToolRepository;
18
import com.devonfw.tools.ide.tool.uv.Uv;
19
import com.devonfw.tools.ide.version.VersionIdentifier;
20

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

26
  private final VersionIdentifier PYTHON_MIN_VERSION = VersionIdentifier.of("3.8.2");
4✔
27

28
  /**
29
   * The constructor.
30
   *
31
   * @param context the {@link IdeContext}.
32
   */
33
  public Python(IdeContext context) {
34

35
    super(context, "python", Set.of(Tag.PYTHON));
6✔
36
  }
1✔
37

38
  /**
39
   * Installs {@code Python} using the {@link Uv#installPython(Path, VersionIdentifier, ProcessContext)} method.
40
   * <p>
41
   * Unlike the base implementation, this method requires the {@link ProcessContext} to perform the installation logic specific to {@code python}.
42
   *
43
   * @param toolRepository the {@link ToolRepository}, unused in this implementation.
44
   * @param resolvedVersion the {@link VersionIdentifier} of the {@code Python} tool to install.
45
   * @param installationPath the target {@link Path} where the tool should be installed.
46
   * @param edition the edition of the tool to install, unused in this implementation.
47
   * @param processContext the {@link ProcessContext} required to install the {@code Python} environment.
48
   */
49
  @Override
50
  protected void performToolInstallation(ToolRepository toolRepository, VersionIdentifier resolvedVersion, Path installationPath,
51
      String edition, ProcessContext processContext) {
52

53
    if (resolvedVersion.compareVersion(PYTHON_MIN_VERSION).isLess()) {
×
54
      throw new CliException("Python version must be at least " + this.PYTHON_MIN_VERSION);
×
55
    }
56

57
    FileAccess fileAccess = this.context.getFileAccess();
×
58
    if (Files.exists(installationPath)) {
×
59
      fileAccess.backup(installationPath);
×
60
    }
61
    Path softwarePath = installationPath.getParent();
×
62
    Uv uv = this.context.getCommandletManager().getCommandlet(Uv.class);
×
63

64
    uv.installPython(softwarePath, resolvedVersion, processContext);
×
65
    renameVenvFolderToPython(fileAccess, softwarePath, installationPath);
×
66
    this.context.writeVersionFile(resolvedVersion, installationPath);
×
67
    createWindowsSymlinkBinFolder(fileAccess, installationPath);
×
68
    this.context.debug("Installed {} in version {} at {}", this.tool, resolvedVersion, installationPath);
×
69
  }
×
70

71
  @Override
72
  public void setEnvironment(EnvironmentContext environmentContext, ToolInstallation toolInstallation, boolean extraInstallation) {
73

74
    super.setEnvironment(environmentContext, toolInstallation, extraInstallation);
×
75
    environmentContext.withEnvVar("VIRTUAL_ENV", toolInstallation.rootDir().toString());
×
76
  }
×
77

78
  @Override
79
  protected boolean isIgnoreSoftwareRepo() {
80

81
    return true;
×
82
  }
83

84
  /**
85
   * 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"
86
   * directory.
87
   *
88
   * @param fileAccess the {@link FileAccess} utility for file operations.
89
   * @param installationPath the path where Python is installed.
90
   */
91
  private void createWindowsSymlinkBinFolder(FileAccess fileAccess, Path installationPath) {
92

93
    if (!this.context.getSystemInfo().isWindows()) {
×
94
      return;
×
95
    }
96
    Path scriptsPath = installationPath.resolve("Scripts");
×
97
    Path binPath = installationPath.resolve("bin");
×
98
    fileAccess.symlink(scriptsPath, binPath);
×
99
  }
×
100

101
  /**
102
   * Renames the ".venv" folder into the installation path (Python).
103
   *
104
   * @param fileAccess the {@link FileAccess} utility for file operations.
105
   * @param softwarePath the path where the software is installed.
106
   * @param installationPath the target path where the ".venv" folder should be moved.
107
   */
108
  private void renameVenvFolderToPython(FileAccess fileAccess, Path softwarePath, Path installationPath) {
109

110
    Path venvPath = softwarePath.resolve(".venv");
×
111
    fileAccess.move(venvPath, installationPath, StandardCopyOption.REPLACE_EXISTING);
×
112
  }
×
113

114
}
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