Skip to content

Conversation

@ivaylo-matov
Copy link
Contributor

This PR fixes the issue where DuplicateCallsToImportShouldBeFine in DynamoPythontests was showing standard output “Error extracting zip file … DSPythonNet3Wheels.Resources..whl”

The problem was that the code tried to unzip embedded wheel files using fake file paths based on their resource names.

Now the code extracts the wheels directly from the resource stream into the site-packages folder instead of building those paths.
pywin32 wheels are still installed using pip as before.

This change should remove the noisy error messages and make the wheel installation more reliable.

image image

@zeusongit
@dnenov

Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

This PR fixes an issue where embedded wheel files were being extracted using fake file paths based on resource names, causing "Error extracting zip file" messages during Python installation. The code now extracts wheels directly from resource streams into the site-packages folder, while pywin32 wheels continue to be installed via pip.

Key Changes:

  • Replaced parallel wheel installation with direct extraction from embedded resource streams
  • Added explicit site-packages directory creation and path construction
  • Separated pywin32 wheels for pip installation from direct extraction logic

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines 379 to 418
foreach (var resName in wheelsAssembly.GetManifestResourceNames())
{
bool isWheel = x.Contains(".whl");
if (isWheel && x.Contains("pywin32-"))
bool isWheel = resName.EndsWith(".whl");
if (!isWheel) continue;

if (resName.Contains("pywin32-"))
{
pipWheelInstall.Add(x);
return false;
pipWheelInstall.Add(resName);
continue;
}

return isWheel;
}).Select(wheel => Python.Included.Installer.InstallWheel(wheelsAssembly, wheel))).ConfigureAwait(false);
using (var stream = wheelsAssembly.GetManifestResourceStream(resName))
{
if (stream == null || stream.Length == 0)
{
continue;
}

using (var zip = new System.IO.Compression.ZipArchive(stream, System.IO.Compression.ZipArchiveMode.Read, false))
{
foreach (var entry in zip.Entries)
{
if (string.IsNullOrEmpty(entry.Name)) continue;

var destPath = Path.Combine(sitePkgsPath, entry.FullName.Replace('/', Path.DirectorySeparatorChar));
var destDir = Path.GetDirectoryName(destPath);
if (!string.IsNullOrEmpty(destDir))
{
Directory.CreateDirectory(destDir);
}

using (var inStream = entry.Open())
using (var outStream = new FileStream(destPath, FileMode.Create, FileAccess.Write, FileShare.None))
{
await inStream.CopyToAsync(outStream).ConfigureAwait(false);
}
}
}
}
}
Copy link

Copilot AI Nov 3, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The foreach loop contains an await statement (line 413), but the loop is not async-aware. This will execute the wheel extractions sequentially rather than in parallel. Consider collecting tasks and using Task.WhenAll() to maintain the parallel execution behavior from the original implementation, which could significantly impact installation performance when multiple wheels need to be extracted.

Copilot uses AI. Check for mistakes.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this could be problematic?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IMO this shouldn’t be a problem. Running the extractions sequentially should be safer and still fast enough since we only have around a dozen wheels.
The original version was parallel, but that can sometimes cause disk thrashing or file-exist race conditions. Given that the speed difference is minimal and our tests were already a bit noisy, keeping the extraction sequential felt like a more stable option.
Happy to revert if you think it’s better to restore the parallel behavior.

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
@twastvedt
Copy link
Contributor

Can you point to a Jenkins run with the error output you were seeing? I'm wary of replacing Python.Included's built-in mechanism for this with our own extraction logic. But I guess if it works...

@zeusongit
Copy link
Contributor

So, how were the tests working with wheel files before?

Can you point to a Jenkins run with the error output you were seeing? I'm wary of replacing Python.Included's built-in mechanism for this with our own extraction logic. But I guess if it works...

There is no error, but we do see logs such as this when running tests:

Screenshot 2025-10-31 121650

@zeusongit
Copy link
Contributor

But I also want to understand why the install option did not work here

@twastvedt
Copy link
Contributor

Looks like it was hitting this exception. But it looks like Python.Included checks whether the files exist already, so not sure why that wasn't working. But I'm also not convinced that it's worth it to do ourselves just to get rid of a few log lines.

@ivaylo-matov
Copy link
Contributor Author

@zeusongit , @twastvedt
Before the wheels were embedded in Python.Included.dll and Python.Included.SciPy.dll. The evaluator called Python.Included.Installer, which knows how to turn its own resource names into real wheel files, so extraction worked.

Now that are using the nuget , the wheels are embedded in DSPythonNet3Wheels.dll. We still want to call Python.Included.Installer (I assume), but that helper expects the Python.Included.Resources naming. With the DSPythonNet3Wheels.Resources names, it doesn’t strip the prefix, so it builds a fake file path and the extraction fails.

@twastvedt
Copy link
Contributor

Python.Included has always been a third-party dll, our wheels were never bundled into that dll, they have always been embedded in the DSPythonNet3Wheels resource file. This file, which bundles the whl files into DSPythonNet3Wheels.dll, has not been changed for a year.

@ivaylo-matov
Copy link
Contributor Author

I was comparing to DSCPython

image

@BogdanZavu
Copy link

So a wheel like numpy for example is successfully installed when you work with Dynamo ?
This failed install is only during that test or it happens only in the pipeline ?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants