-
-
Notifications
You must be signed in to change notification settings - Fork 1.3k
[BUG] ensure_local_distutils seems to fail inside PyInstaller .exe (for new setuptools versions >= 60) #3089
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
Comments
Sorry for the trouble. There's a lot going on here that we'll need to tease apart.
That's not the case. The latest releases of Setuptools still support Python 3.7. It is the case that starting with Setuptools 60, however, Setuptools is adopting distutils (because stdlib distutils is expected to go away in Python 3.12), supplying its own copy internally and using the Can you put together a more complete reproducer, preferably a minimum one that encounters the error? Are you using setuptools to build your project or are you using setuptools inside your project (or both)? I notice you're using |
Thanks a lot for the quick reply.
I agree. import setuptools
from distutils.core import setup from setuptools import setup
The project is a utility for deploying apps on our org's local server, so distutils comes in handy there. The project used distutils only and did not import setuptools. As I tried to explain, the exe threw an error that 'setuptools' could not be imported, specifically when the line So my next step was explicitly adding the line "import setuptools" into our project to ensure that PyInstaller will bundle setuptools==60.5.0 inside of the exe. That lead to the described error inside So in summary the project/exe builds other projects that import setuptools in their
Will do, give me some time. |
I was able to repro this on 3.7 - 3.10 and as you suggested this issue was introduced in setuptools==60.0.0 Below is a PowerShell script which downloads and installs Python, then installs setuptools and pyinstaller, and then creates an exe out of a file which just imports the two packages. # Run me as administrator
# https://stackoverflow.com/q/5944180/2111778
# powershell -ExecutionPolicy Bypass .\repro_setuptools_60_bug.ps1
$pythonVersion = @("3.7.7", "3.8.10", "3.9.10", "3.10.2")[3]
$pythonUrl = "https://www.python.org/ftp/python/$pythonVersion/python-$pythonVersion.exe"
$pythonInstallDirDir = "C:\Temp\Test1"
$pythonDownloadPath = "$pythonInstallDirDir\python-installer-$pythonVersion.exe"
$pythonInstallDir = "$pythonInstallDirDir\Python$pythonVersion"
if (Test-Path $pythonInstallDirDir) {
Remove-Item -Recurse -Force $pythonInstallDirDir
sleep 10 # removals are not instant on Windows
}
mkdir $pythonInstallDirDir
cd $pythonInstallDirDir
(New-Object Net.WebClient).DownloadFile($pythonUrl, $pythonDownloadPath)
# For some reason the installer exists right away so sleep until the install appears done
& $pythonDownloadPath /quiet InstallAllUsers=0 Include_test=0 DefaultJustForMeTargetDir=$pythonInstallDir
echo "Python installer exited"
while (-Not (Test-Path "$pythonInstallDir\Scripts\pip.exe")) {
sleep 1
}
echo "Pip install done. Waiting 20 seconds for Python install to finish"
sleep 20
$pythonExe = "$pythonInstallDir\python.exe"
& $pythonExe -m pip install setuptools==60.0.0 pyinstaller==4.8
mkdir "$pythonInstallDirDir\project1"
Set-Content "$pythonInstallDirDir\project1\repro_exe.py" "import setuptools; import distutils"
& "$pythonInstallDir\Scripts\pyinstaller.exe" --onefile "$pythonInstallDirDir\project1\repro_exe.py"
# This line reproduces the error (AssertionError inside ensure_local_distutils)
& .\dist\repro_exe.exe
& $pythonDownloadPath /quiet /uninstall
sleep 40 Results:
It might be worth trying different versions of PyInstaller. I know it extracts packages in some sort of Temp folder (as you can see in the original traceback), and the reason an AssertionError is thrown is that there is an assert that "_distutils" is somewhere in the path (which it isn't, the underscore is missing) |
On second thought my PowerShell script might overcomplicate things, plus the Python installer fails with exit code 0x666 if there is already a newer version on the system. So here a short manual guide assuming a pre-existing Python install.
import setuptools; import distutils
This should produce a file
2a) I just found this. Note that the file import setuptools produces a different traceback:
2b) Note that the file import distutils; import setuptools produces the same error as 2a but with an additional warning:
|
I tried to look at this myself a bit and it appears the expected file location is
i.e. setuptools replaces distutils with its own bundled version. While the actual value we get in the exe is the original distutils
I tried to follow the call chain unsuccessfully
but sadly the trace runs dry there, in fact my print statements stop working inside of |
I was able to do some additional debugging by replacing import _frozen_importlib as _bootstrap with from . import _bootstrap
__bootstrap._setup(sys, _imp) inside of Findings: In Python,
So a potential fix would extend DistutilsMetaFinder to also be able to find the relevant |
I'm noticing another issue. The So I am perplexed how the I guess it could be a leftover from the exe build process? But then why don't my changes make it? |
Are you sure the code isn't being loaded from a cache? What is the value of |
The value is |
I printed a trace now based on print statements. TL;DR when importing Loading said module fails in the exe. In vanilla Python this module is found by the |
There is a function
as expected. Inside the exe the path also seems correct
The only problem is that the directory does not exist by the time Which makes no sense to me because I thought our call stack looked like this
so the Maybe this is a PyInstaller issue after all where it has access to multiple versions of |
Yeah I'm giving up on this now. Nothing here makes sense to me. |
Reproduced this on Windows 10 in a fresh conda environment with the following:
In my case, step 2a (i.e. only |
Thanks a lot for noticing my report and implementing a workaround in I no longer rely on I am not sure if this issue could have other effects (maybe in |
I regret having lost track of this issue. I appreciate all the work that went into the investigation and for the PyInstaller maintainers to provide support for this hack. I don't believe there's any more that's needed at this stage. If py2exe needs guidance, feel free to ping this issue or open a new one (and mention me). |
setuptools version
60.5.0 (>= 60.0.0 seems affected)
Python version
3.7.7 on win32 (3.7 - 3.10 seem affected)
OS
Windows 10
Additional environment information
No response
Description
I described this issue in detail on StackOverflow: https://stackoverflow.com/q/71027006/2111778 Below a copy:
I am trying to convert some Python code into an
.exe
with PyInstaller. My code uses distutils, which has already caused me some head scratching in the past as it seems to duplicate setuptools functionality. It also requires e.g. an unused import of setuptools to work properly which seems very unpythonic to me.My first attempt to create an exe failed with the error message
Module not found: 'setuptools'
because my code only doesimport distutils
explicitly (this works fine, but not inside the exe build). But knowing about the "unused import trick" I changed that to essentiallyimport setuptools; import distutils
, which basically instructs PyInstaller to include thesetuptools
module as well.My script runs fine but after I turn it into an exe I get a traceback inside of the suspicious
_distutils_hack
submodule of setuptools. And yes it just prints a file name with no context.I am using
Python 3.7
pyinstaller==4.8
(Jan 2022) for Windowsdistutils==3.7.7
(built-in)setuptools==60.5.0
(Jan 2022)Apparently,
setuptools
is listed on PyPI and thus upgradable, butdistutils
is not listed on PyPI and thus not upgradable (the version is bundled with Python).A workaround I found was downgrading to any version before 60
Expected behavior
See above
How to Reproduce
See above
Output
See above
The text was updated successfully, but these errors were encountered: