-
Notifications
You must be signed in to change notification settings - Fork 38
Bug/ap 25397 python pref selection error #77
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
3f6e853
af1ecfc
dcc0873
9f93b43
2a5034b
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -48,6 +48,8 @@ | |||||||||||
| */ | ||||||||||||
| package org.knime.python3; | ||||||||||||
|
|
||||||||||||
| import java.io.File; | ||||||||||||
| import java.nio.file.Path; | ||||||||||||
| import java.util.List; | ||||||||||||
|
|
||||||||||||
| import org.knime.externalprocessprovider.ExternalProcessProvider; | ||||||||||||
|
|
@@ -78,4 +80,52 @@ public SimplePythonCommand(final String... commands) { | |||||||||||
| public SimplePythonCommand(final List<String> command) { | ||||||||||||
| super(command); | ||||||||||||
| } | ||||||||||||
|
|
||||||||||||
| /** | ||||||||||||
| * Creates a {@link ProcessBuilder} for this command, prepending the Python executable's conda environment | ||||||||||||
| * directories to {@code PATH}. On Windows, conda/pixi environments require several sub-directories to be on | ||||||||||||
| * {@code PATH} for proper process startup: | ||||||||||||
| * <ul> | ||||||||||||
| * <li>The env root (contains the Python DLL)</li> | ||||||||||||
| * <li>{@code Library/bin} (contains vcruntime, openssl, and other SxS-manifest DLLs)</li> | ||||||||||||
| * <li>{@code Library/mingw-w64/bin} (contains mingw toolchain DLLs)</li> | ||||||||||||
| * <li>{@code Library/usr/bin} (contains misc tools)</li> | ||||||||||||
| * <li>{@code Scripts} (contains pip, etc.)</li> | ||||||||||||
| * </ul> | ||||||||||||
| * Without these, Python 3.12+ fails at startup with a Windows SxS assembly error because VC++ runtime DLLs | ||||||||||||
| * cannot be located. Only directories that actually exist on disk are prepended to avoid polluting {@code PATH} | ||||||||||||
| * for non-conda environments. | ||||||||||||
| */ | ||||||||||||
| @Override | ||||||||||||
| public ProcessBuilder createProcessBuilder() { | ||||||||||||
| final var pb = super.createProcessBuilder(); | ||||||||||||
| final Path executableDir = getExecutablePath().getParent(); | ||||||||||||
| if (executableDir != null) { | ||||||||||||
| final var env = pb.environment(); | ||||||||||||
| // ProcessBuilder.environment() on Windows stores keys case-insensitively but | ||||||||||||
| // preserves the original casing. Find the existing key to avoid duplicates. | ||||||||||||
| final String pathKey = env.keySet().stream() // | ||||||||||||
| .filter(k -> k.equalsIgnoreCase("PATH")) // | ||||||||||||
| .findFirst() // | ||||||||||||
| .orElse("PATH"); | ||||||||||||
| final String existingPath = env.getOrDefault(pathKey, ""); | ||||||||||||
|
|
||||||||||||
| // Standard conda/pixi activation paths for Windows, in activation order. | ||||||||||||
| final var dirsToAdd = new StringBuilder(); | ||||||||||||
| for (final String subDir : new String[]{"", "Library\\bin", "Library\\mingw-w64\\bin", | ||||||||||||
| "Library\\usr\\bin", "Scripts"}) { | ||||||||||||
| final var candidate = subDir.isEmpty() ? executableDir : executableDir.resolve(subDir); | ||||||||||||
| if (candidate.toFile().isDirectory()) { | ||||||||||||
|
Comment on lines
+100
to
+118
|
||||||||||||
| if (dirsToAdd.length() > 0) { | ||||||||||||
| dirsToAdd.append(File.pathSeparator); | ||||||||||||
| } | ||||||||||||
| dirsToAdd.append(candidate); | ||||||||||||
| } | ||||||||||||
| } | ||||||||||||
| if (dirsToAdd.length() > 0) { | ||||||||||||
| env.put(pathKey, dirsToAdd + File.pathSeparator + existingPath); | ||||||||||||
|
||||||||||||
| env.put(pathKey, dirsToAdd + File.pathSeparator + existingPath); | |
| final String newPath = existingPath.isEmpty() | |
| ? dirsToAdd.toString() | |
| : dirsToAdd + File.pathSeparator + existingPath; | |
| env.put(pathKey, newPath); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If reading stdout (
IOUtils.copy(in, ...)) throws, the method exits via the outercatch (IOException ...)without joining the stderr thread or ensuring the process/streams are cleaned up, which can leave a background thread running and resources open. Consider joining the stderr reader in afinallyblock (and/or using an executor) so it is always terminated before returning, even on exceptions.