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

devonfw / IDEasy / 35612692096

21 Sep 2026 02:31PM UTC coverage: 74.245% (-0.001%) from 74.246%
35612692096

Pull #2523

github

web-flow
Merge 9e6f97f2d into a6809790c
Pull Request #2523: #2484 tab completion for ide install python triggers uv installation

5717 of 8554 branches covered (66.83%)

Branch coverage included in aggregate %.

14820 of 19107 relevant lines covered (77.56%)

3.32 hits per line

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

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

3
import java.util.ArrayList;
4
import java.util.Comparator;
5
import java.util.List;
6

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

10
import com.devonfw.tools.ide.context.IdeContext;
11
import com.devonfw.tools.ide.process.ProcessContext;
12
import com.devonfw.tools.ide.process.ProcessErrorHandling;
13
import com.devonfw.tools.ide.process.ProcessMode;
14
import com.devonfw.tools.ide.process.ProcessResult;
15
import com.devonfw.tools.ide.tool.ToolCommandlet;
16
import com.devonfw.tools.ide.tool.repository.AbstractToolRepository;
17
import com.devonfw.tools.ide.tool.uv.Uv;
18
import com.devonfw.tools.ide.url.model.file.UrlDownloadFileMetadata;
19
import com.devonfw.tools.ide.version.VersionIdentifier;
20

21
/**
22
 * {@link com.devonfw.tools.ide.tool.repository.ToolRepository ToolRepository} for Python.
23
 */
24
public class PythonRepository extends AbstractToolRepository {
25

26
  /** {@link #getId() ID} of this repository. */
27
  public static final String ID = "python";
28

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

31
  private List<VersionIdentifier> cachedVersions;
32

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

40
    super(context);
3✔
41
  }
1✔
42

43
  @Override
44
  public String getId() {
45

46
    return ID;
×
47
  }
48

49
  @Override
50
  public List<String> getSortedEditions(String tool) {
51

52
    return List.of(tool);
3✔
53
  }
54

55
  @Override
56
  public List<VersionIdentifier> getSortedVersions(String tool, String edition, ToolCommandlet toolCommandlet) {
57

58
    if (this.cachedVersions == null) {
3✔
59
      this.cachedVersions = computeSortedVersions();
4✔
60
    }
61
    return this.cachedVersions;
3✔
62
  }
63

64
  private List<VersionIdentifier> computeSortedVersions() {
65

66
    List<PythonUvListEntry> entries = fetchUvPythonList();
3✔
67
    List<VersionIdentifier> versions = new ArrayList<>();
4✔
68
    for (PythonUvListEntry entry : entries) {
10✔
69
      if (entry.isCpython()) {
3✔
70
        VersionIdentifier version = VersionIdentifier.of(entry.version());
4✔
71
        if ((version != null) && !versions.contains(version)) {
6!
72
          versions.add(version);
4✔
73
        }
74
      }
75
    }
1✔
76
    versions.sort(Comparator.reverseOrder());
3✔
77
    LOG.debug("Found {} Python version(s) available via uv for the current platform.", versions.size());
6✔
78
    return versions;
2✔
79
  }
80

81
  /**
82
   * Runs {@code uv python list} and parses the result. Extracted as a protected method so tests can stub the {@code uv} is not installed.
83
   *
84
   * @return the parsed {@link PythonUvListEntry entries}, or an empty list if {@code uv} is not installed.
85
   */
86
  protected List<PythonUvListEntry> fetchUvPythonList() {
87

88
    Uv uv = this.context.getCommandletManager().getCommandlet(Uv.class);
7✔
89
    if (!uv.isInstalled()) {
3✔
90
      LOG.warn("uv is not installed, run 'ide install uv'");
3✔
91
      return List.of();
2✔
92
    }
93
    ProcessContext pc = this.context.newProcess().errorHandling(ProcessErrorHandling.THROW_CLI);
6✔
94
    this.context.setEnvironmentOfInstalledTools(pc);
4✔
95
    ProcessResult result = uv.runTool(pc, ProcessMode.DEFAULT_CAPTURE,
12✔
96
        List.of("python", "list", "--all-versions", "--only-downloads", "--output-format", "json", "--no-config"));
1✔
97
    return uv.parsePythonListJson(result.getOut());
5✔
98
  }
99

100
  @Override
101
  protected UrlDownloadFileMetadata getMetadata(String tool, String edition, VersionIdentifier version, ToolCommandlet toolCommandlet) {
102

103
    throw new UnsupportedOperationException(
×
104
        "Python is installed via uv and is never downloaded from a URL. This repository only resolves versions.");
105
  }
106
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE TRIAL · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc