I have only recently started with py2exe, and I would like to use py2exe with MINGW64 Python3 programs (and corresponding libraries). However, the first example I tried failed to build.
After that, I found the https://www.py2exe.org/index.cgi/TroubleshootingImportErrors page, where it is noted:
Check that zipextimporter works on your system
zipextimporter is the starting component of py2exe that may cause problems. To debug it you will need _memimporter.pyd binary module. These modules can be found in binary py2exe distributions for your Python version (I unpack .exe distribution with 7Zip).
There is also a test script, but it is in Python 2 (last update of that page is 2011-01-07); so I converted it to Python 3 syntax:
import zipextimporter
zipextimporter.install()
import sys
sys.path.insert(0, "lib.zip")
import _socket
print(_socket)
# <module '_socket' from 'lib.zip\_socket.pyd'>
print(_socket.__file__)
# 'lib.zip\\_socket.pyd'
print(_socket.__loader__)
# <ZipExtensionImporter object 'lib.zip'>
# Reloading also works correctly:
print(_socket is reload(_socket))
# True
But when I run it, I get:
$ python3 test_zipextimporter.py
Traceback (most recent call last):
File "D:/msys64/tmp/test_zipextimporter.py", line 1, in <module>
import zipextimporter
File "D:/msys64/mingw64/lib/python3.11/site-packages/zipextimporter.py", line 51, in <module>
import _memimporter
ModuleNotFoundError: No module named '_memimporter'
So, as the note above says, I need a _memimporter.pyd binary module; there is no such file in the package directly:
$ pacman -Ql mingw-w64-x86_64-python-py2exe | grep _mem
$
However, the note also states "These modules can be found in binary py2exe distributions for your Python version (I unpack .exe distribution with 7Zip)." Currently there are these binary files in the package:
$ pacman -Ql mingw-w64-x86_64-python-py2exe | grep '\.exe\|\.dll'
mingw-w64-x86_64-python-py2exe /mingw64/lib/python3.11/site-packages/py2exe/resources.dll
mingw-w64-x86_64-python-py2exe /mingw64/lib/python3.11/site-packages/py2exe/run-py311-mingw_x86_64.exe
mingw-w64-x86_64-python-py2exe /mingw64/lib/python3.11/site-packages/py2exe/run_ctypes_dll-py311-mingw_x86_64.dll
mingw-w64-x86_64-python-py2exe /mingw64/lib/python3.11/site-packages/py2exe/run_w-py311-mingw_x86_64.exe
None of these can be listed with say unzip -l; but they can be listed with 7z l - unfortunately, I see nothing there resembling _memimporter.pyd - both .exes show this structure of files:
$ 7z l /mingw64/lib/python3.11/site-packages/py2exe/run_w-py311-mingw_x86_64.exe
...
Date Time Attr Size Compressed Name
------------------- ----- ------------ ------------ ------------------------
2023-12-27 10:55:20 ..... 24064 24064 .text
2023-12-27 10:55:20 ..... 1024 1024 .data
2023-12-27 10:55:20 ..... 6656 6656 .rdata
2023-12-27 10:55:20 ..... 2048 2048 .pdata
2023-12-27 10:55:20 ..... 2048 2048 .xdata
2023-12-27 10:55:20 ..... 0 0 .bss
2023-12-27 10:55:20 ..... 2048 2048 .edata
2023-12-27 10:55:20 ..... 4096 4096 .idata
2023-12-27 10:55:20 ..... 512 512 .CRT
2023-12-27 10:55:20 ..... 512 512 .tls
..... 766 744 .rsrc/1033/ICON/1.ico
..... 20 20 .rsrc/1033/GROUP_ICON/1
..... 1167 1167 .rsrc/0/MANIFEST/1
2023-12-27 10:55:20 ..... 512 512 .reloc
------------------- ----- ------------ ------------ ------------------------
2023-12-27 10:55:20 45473 45451 14 files
I've tried to compare with the vanilla py2exe download, and results are similar:
$ wget https://files.pythonhosted.org/packages/b1/07/f45b201eb8c3fea1af6a9bd9f733479aa9d009139ce2396e06db7aa778c8/py2exe-0.13.0.1-cp311-cp311-win_amd64.whl
# ...
$ mkdir py2exe_0.13.0.1
$ (cd py2exe_0.13.0.1; unzip ../py2exe-0.13.0.1-cp311-cp311-win_amd64.whl)
# ...
$ 7z l py2exe_0.13.0.1/py2exe/run-py3.11-win-amd64.exe
# ...
Date Time Attr Size Compressed Name
------------------- ----- ------------ ------------ ------------------------
2023-10-07 18:15:11 ..... 20480 20480 .text
2023-10-07 18:15:11 ..... 11264 11264 .rdata
2023-10-07 18:15:11 ..... 512 512 .data
2023-10-07 18:15:11 ..... 2048 2048 .pdata
..... 766 744 .rsrc/ICON/1.ico
..... 20 20 .rsrc/GROUP_ICON/1
..... 381 381 .rsrc/MANIFEST/1
2023-10-07 18:15:11 ..... 512 512 .reloc
------------------- ----- ------------ ------------ ------------------------
2023-10-07 18:15:11 35983 35961 8 files
I guess this _memimporter is still a thing, because after all my test script fails with "No module named '_memimporter'"; and also there are still references in the Python code of the package:
$ grep -rI _memimporter /mingw64/lib/python3.11/site-packages/py2exe
/mingw64/lib/python3.11/site-packages/py2exe/distutils_buildexe.py:## self.excludes.append("_memimporter") # builtin in run_*.exe and run_*.dll
/mingw64/lib/python3.11/site-packages/py2exe/hooks.py:# _memimporter can be excluded because it is built into the run-stub.
/mingw64/lib/python3.11/site-packages/py2exe/hooks.py:_memimporter
... but, I have to ask - is this _memimporter.pyd still a thing - and if so, where do I find it?
Right, this was a pain... Anyways, as for the first part of the question -
_memimporteris apparently still a thing, since there are recent discussions:As for getting the
_memimporter, it's again tricky, because you have to build from source. There is a historical version https://github.com/mitre/caldera-py2exe - but because of that recent patch above, it's best to build directly from the main py2exe git repo directly:Now, the question is which command to use to build - unfortunately, the main repo README.md does not specify this (it just mentions
pip install py2exe). In the historical repo, a commandpython setup.py bdistis mentioned, however it seems to be deprecatet, as it raises:I finally found the command that the MINGW64 package uses to build in the corresponding MINGW-packages/mingw-w64-python-py2exe/PKGBUILD file.
Also, note that I had to install:
Then, the direct py2exe source, as is, will not compile, so one also has to apply the patches mentioned in the PKGBUILD file. So we have:
OK, so we can build now - there is still a deprecation warning, but the build will succeed:
Right - so the trick here, is that an
_memimporter.pydfile did NOT build, only an.ofile:If we inspect the build log, we'll see that this
.ofile gets built directly intorun-py311-mingw_x86_64.exe:... which is probably why it is impossible to extract a
_memimporter.pydfrom the.exe.So, now we have
.ofile, but we need.pyd- I found a hint in How to create a .pyd file? (thankfully, also with a reference to MSYS2/MINGW64) - so eventually, that command is:So, now we have a
_memimporter.pyd; and to have it available so the test script will work, we copy it to/mingw64/lib/python3.11/site-packages/(for some reason, copying it to/mingw64/lib/python3.11/site-packages/py2exedoes not work):Then we can finally test the import and see no errors:
And now we can run the test script from the OP - however, for some reason, I do not get printouts for
_socket:... but at least there are no errors related to
_memimporter.