-
Notifications
You must be signed in to change notification settings - Fork 38
Enh/ap 25245 pixi env creator #47
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
ce416a1
ecb8f80
566f3c8
9682bbf
65cbd5e
5644fcb
42072d1
a840697
dce5538
c8b6f16
0691a21
54aa7b5
d461935
b2afed7
8ba9737
6916163
0e0a587
75264f0
aed540d
0e150ca
4d32cbd
97d8a99
e11c36a
565e579
91734ff
117afb5
4e14218
313606c
470e5e0
448dcf1
21c860d
6230861
6441929
276cf92
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 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -50,8 +50,10 @@ | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import org.knime.core.node.BufferedDataTable; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import org.knime.core.node.context.ports.PortsConfiguration; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import org.knime.core.node.port.PortObject; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import org.knime.core.node.port.PortType; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import org.knime.core.node.port.image.ImagePortObject; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import org.knime.pixi.port.PythonEnvironmentPortObject; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import org.knime.python2.port.PickledObjectFileStorePortObject; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import org.knime.python2.ports.DataTableInputPort; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import org.knime.python2.ports.DataTableOutputPort; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -61,6 +63,7 @@ | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import org.knime.python2.ports.PickledObjectInputPort; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import org.knime.python2.ports.PickledObjectOutputPort; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| /** | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| * @author Marcel Wiedenmann, KNIME GmbH, Konstanz, Germany | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| * @author Benjamin Wilhelm, KNIME GmbH, Berlin, Germany | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -71,6 +74,27 @@ private PortsConfigurationUtils() { | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Utility class | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| /** | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| * Check if the ports configuration contains a Python environment port. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| * | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| * @param config the ports configuration | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| * @return true if a Python environment port is present | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| */ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| public static boolean hasPythonEnvironmentPort(final PortsConfiguration config) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| final PortType[] inTypes = config.getInputPorts(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| try { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Check if any input port is a PythonEnvironmentPortObject | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| for (final PortType inType : inTypes) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (isPythonEnvironmentPort(inType)) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return true; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } catch (NoClassDefFoundError e) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Python environment bundle is not available - this is fine since it's optional | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return false; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| /** | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| * Extract the input ports from the given ports configuration. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| * | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -81,9 +105,21 @@ public static InputPort[] createInputPorts(final PortsConfiguration config) { | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| final PortType[] inTypes = config.getInputPorts(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| int inTableIndex = 0; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| int inObjectIndex = 0; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| final var inPorts = new InputPort[inTypes.length]; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Count non-environment ports for the result array | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| int numNonEnvironmentPorts = 0; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| for (final PortType inType : inTypes) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (!isPythonEnvironmentPort(inType)) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| numNonEnvironmentPorts++; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| final var inPorts = new InputPort[numNonEnvironmentPorts]; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| int portIndex = 0; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| for (int i = 0; i < inTypes.length; i++) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| final PortType inType = inTypes[i]; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Skip Python environment ports - they are not InputPorts in the traditional sense | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (isPythonEnvironmentPort(inType)) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| continue; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| final InputPort inPort; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (BufferedDataTable.TYPE.equals(inType)) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| inPort = new DataTableInputPort("knio.input_tables[" + inTableIndex++ + "]"); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -92,11 +128,26 @@ public static InputPort[] createInputPorts(final PortsConfiguration config) { | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } else { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| throw new IllegalStateException("Unsupported input type: " + inType.getName()); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| inPorts[i] = inPort; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| inPorts[portIndex++] = inPort; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return inPorts; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| /** | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| * Check if a port type is a Python environment port. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| * | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| * @param inType the port type to check | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| * @return true if the port type is a Python environment port | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| */ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| public static boolean isPythonEnvironmentPort(final PortType inType) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| try { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return inType.equals(PythonEnvironmentPortObject.TYPE) || inType.equals(PythonEnvironmentPortObject.TYPE_OPTIONAL); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } catch (NoClassDefFoundError e) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Python environment bundle is not available - this is fine since it's optional | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return false; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| /** | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| * Extract the output ports from the given ports configuration. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| * | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -135,4 +186,48 @@ public static OutputPort[] createOutputPorts(final PortsConfiguration config) { | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| public static OutputPort createPickledObjectOutputPort(final int outObjectSuffix) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return new PickledObjectOutputPort("knio.output_objects[" + outObjectSuffix + "]"); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| /** | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| * Extract the Python environment port object from the input port objects, if present. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| * | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| * @param inObjects the input port objects | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| * @return the Python environment port object, or null if not present | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| * @throws IllegalArgumentException if a Python environment port is expected but not found | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| */ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| public static PythonEnvironmentPortObject extractPythonEnvironmentPort(final PortObject[] inObjects) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| for (final PortObject inObject : inObjects) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (inObject instanceof PythonEnvironmentPortObject envPort) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return envPort; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| throw new IllegalArgumentException( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "Expected a Python environment port object in the input ports, but none was found."); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| /*public static void installPythonEnvironmentIfPresent(final PortsConfiguration config, final PortObject[] inObjects, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| final ExecutionMonitor exec) throws IOException, CanceledExecutionException { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| final PythonEnvironmentPortObject envPort = extractPythonEnvironmentPort(config, inObjects); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (envPort != null) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| PythonEnvironmentPortObject.installPythonEnvironmentWithProgress(config, inObjects, exec); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }*/ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+207
to
+214
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| /*public static void installPythonEnvironmentIfPresent(final PortsConfiguration config, final PortObject[] inObjects, | |
| final ExecutionMonitor exec) throws IOException, CanceledExecutionException { | |
| final PythonEnvironmentPortObject envPort = extractPythonEnvironmentPort(config, inObjects); | |
| if (envPort != null) { | |
| PythonEnvironmentPortObject.installPythonEnvironmentWithProgress(config, inObjects, exec); | |
| } | |
| }*/ |
Copilot
AI
Feb 12, 2026
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.
This code assumes exactly one environment port exists, but doesn't validate this assumption. If there are zero or multiple environment ports, this will create an incorrectly-sized array and may lead to ArrayIndexOutOfBoundsException.
| // Find and exclude the environment port | |
| final PortObject[] filtered = new PortObject[inObjects.length - 1]; | |
| int filteredIndex = 0; | |
| for (int i = 0; i < inObjects.length; i++) { | |
| if (!(inObjects[i] instanceof PythonEnvironmentPortObject)) { | |
| filtered[filteredIndex++] = inObjects[i]; | |
| // First count how many environment ports are present | |
| int envPortCount = 0; | |
| for (final PortObject inObject : inObjects) { | |
| if (inObject instanceof PythonEnvironmentPortObject) { | |
| envPortCount++; | |
| } | |
| } | |
| // If there is no environment port, nothing to filter out | |
| if (envPortCount == 0) { | |
| return inObjects; | |
| } | |
| // Find and exclude all environment ports | |
| final PortObject[] filtered = new PortObject[inObjects.length - envPortCount]; | |
| int filteredIndex = 0; | |
| for (final PortObject inObject : inObjects) { | |
| if (!(inObject instanceof PythonEnvironmentPortObject)) { | |
| filtered[filteredIndex++] = inObject; |
Copilot
AI
Feb 11, 2026
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.
filterEnvironmentPort assumes exactly one environment port and blindly allocates inObjects.length - 1. If the configuration ever contains 0 or >1 environment ports (e.g., future changes, misconfiguration, or different port typing), this can either drop a data port or return an array containing trailing nulls (risking downstream NPEs). Allocate the filtered array by counting non-environment ports (based on inTypes) and fill it accordingly, or build a dynamic list and convert to array to guarantee correct sizing.
| final PortObject[] filtered = new PortObject[inObjects.length - 1]; | |
| int filteredIndex = 0; | |
| for (int i = 0; i < inTypes.length && i < inObjects.length; i++) { | |
| if (!isPythonEnvironmentPort(inTypes[i])) { | |
| filtered[filteredIndex++] = inObjects[i]; | |
| } | |
| } | |
| final int max = Math.min(inTypes.length, inObjects.length); | |
| // First pass: count non-environment ports within the overlapping range | |
| int nonEnvCount = 0; | |
| for (int i = 0; i < max; i++) { | |
| if (!isPythonEnvironmentPort(inTypes[i])) { | |
| nonEnvCount++; | |
| } | |
| } | |
| // Any remaining PortObjects beyond the typed range are treated as non-environment ports | |
| if (inObjects.length > max) { | |
| nonEnvCount += inObjects.length - max; | |
| } | |
| final PortObject[] filtered = new PortObject[nonEnvCount]; | |
| int filteredIndex = 0; | |
| // Second pass: copy non-environment ports from the overlapping range | |
| for (int i = 0; i < max; i++) { | |
| if (!isPythonEnvironmentPort(inTypes[i])) { | |
| filtered[filteredIndex++] = inObjects[i]; | |
| } | |
| } | |
| // Third pass: copy any remaining ports beyond the typed range | |
| for (int i = max; i < inObjects.length; i++) { | |
| filtered[filteredIndex++] = inObjects[i]; | |
| } |
Copilot
AI
Feb 13, 2026
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.
The filterEnvironmentPort method assumes exactly one environment port exists and creates an array with length - 1. If there's no environment port in the array, this will create an array that's too small and cause an ArrayIndexOutOfBoundsException. The method should either count the number of environment ports first or check if any exist before creating the filtered array.
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.
The minimum version requirement for org.knime.core.ui has been lowered from 5.11.0 to 5.10.0, and for org.knime.workbench.editor from 5.10.0 to 5.9.0. These changes appear unrelated to the PR's purpose of adding pixi environment support. Verify that these version downgrades are intentional and necessary, as they may allow the bundle to run with older, potentially incompatible versions of these dependencies.