I’m looking for some advice about the best way to distribute Python.Net with my application. It seems that I have two options:
1. My application installer runs pip install pythonnet
The downside is that the customer needs to have internet access at the time of the install.
2. Bundle the Python.Net files with my application to allow offline installation
I like the idea of a ‘standalone’ installer that can be run offline, however is this a good idea? It needs to install the correct version of Python.Net that matches the version of Python that the customer has installed.
I tried the following steps:
C:\mkdir download pythonnet
cd download pythonnet
pip download pythonnet <-- this gets two files: pythonnet-2.5.2.tar.gz and pycparser-2.20-py2.py3-none-any.whl
<disconnect from the internet>
pip install C:\pythonnet_download\pythonnet-2.5.2.tar.gz
However, this gives the error:
Processing c:\pythonnet_download\pythonnet-2.5.2.tar.gz
Requirement already satisfied: pycparser in c:\program files\python39\lib\site-packages (from pythonnet==2.5.2) (2.20)
Building wheels for collected packages: pythonnet
Building wheel for pythonnet (setup.py) ... error
ERROR: Command errored out with exit status 1:
command: 'c:\program files\python39\python.exe' -u -c 'import sys, setuptools, tokenize; sys.argv[0] = '"'"'C:\\Users\\vincluff\\AppData\\Local\\Temp\\pip-req-build-bgue1v76\\setup.py'"'"'; __file__='"'"'C:\\Users\\vincluff\\AppData\\Local\\Temp\\pip-req-build-bgue1v76\\setup.py'"'"';f=getattr(tokenize, '"'"'open'"'"', open)(__file__);code=f.read().replace('"'"'\r\n'"'"', '"'"'\n'"'"');f.close();exec(compile(code, __file__, '"'"'exec'"'"'))' bdist_wheel -d 'C:\Users\vincluff\AppData\Local\Temp\pip-wheel-s9qap8ze'
cwd: C:\Users\vincluff\AppData\Local\Temp\pip-req-build-bgue1v76\
Complete output (44 lines):
running bdist_wheel
running build
running build_ext
Checking for updates from https://www.nuget.org/api/v2/.
The remote name could not be resolved: 'www.nuget.org'
Traceback (most recent call last):
File "<string>", line 1, in <module>
File "C:\Users\vincluff\AppData\Local\Temp\pip-req-build-bgue1v76\setup.py", line 630, in <module>
setup(
File "c:\program files\python39\lib\site-packages\setuptools\__init__.py", line 165, in setup
return distutils.core.setup(**attrs)
File "c:\program files\python39\lib\distutils\core.py", line 148, in setup
dist.run_commands()
File "c:\program files\python39\lib\distutils\dist.py", line 966, in run_commands
self.run_command(cmd)
File "c:\program files\python39\lib\distutils\dist.py", line 985, in run_command
cmd_obj.run()
File "C:\Users\vincluff\AppData\Local\Temp\pip-req-build-bgue1v76\setup.py", line 612, in run
return bdist_wheel.bdist_wheel.run(self)
File "C:\Users\vincluff\AppData\Roaming\Python\Python39\site-packages\wheel\bdist_wheel.py", line 290, in run
self.run_command('build')
File "c:\program files\python39\lib\distutils\cmd.py", line 313, in run_command
self.distribution.run_command(command)
File "c:\program files\python39\lib\distutils\dist.py", line 985, in run_command
cmd_obj.run()
File "c:\program files\python39\lib\distutils\command\build.py", line 135, in run
self.run_command(cmd_name)
File "c:\program files\python39\lib\distutils\cmd.py", line 313, in run_command
self.distribution.run_command(command)
File "c:\program files\python39\lib\distutils\dist.py", line 985, in run_command
cmd_obj.run()
File "c:\program files\python39\lib\distutils\command\build_ext.py", line 340, in run
self.build_extensions()
File "c:\program files\python39\lib\distutils\command\build_ext.py", line 449, in build_extensions
self._build_extensions_serial()
File "c:\program files\python39\lib\distutils\command\build_ext.py", line 474, in _build_extensions_serial
self.build_extension(ext)
File "C:\Users\vincluff\AppData\Local\Temp\pip-req-build-bgue1v76\setup.py", line 249, in build_extension
self._install_packages()
File "C:\Users\vincluff\AppData\Local\Temp\pip-req-build-bgue1v76\setup.py", line 438, in _install_packages
subprocess.check_call(cmd, shell=use_shell)
File "c:\program files\python39\lib\subprocess.py", line 373, in check_call
raise CalledProcessError(retcode, cmd)
subprocess.CalledProcessError: Command 'tools\nuget\nuget.exe update -self' returned non-zero exit status 1.
----------------------------------------
ERROR: Failed building wheel for pythonnet
Running setup.py clean for pythonnet
Failed to build pythonnet
Installing collected packages: pythonnet
Running setup.py install for pythonnet ... error
ERROR: Command errored out with exit status 1:
command: 'c:\program files\python39\python.exe' -u -c 'import sys, setuptools, tokenize; sys.argv[0] = '"'"'C:\\Users\\vincluff\\AppData\\Local\\Temp\\pip-req-build-bgue1v76\\setup.py'"'"'; __file__='"'"'C:\\Users\\vincluff\\AppData\\Local\\Temp\\pip-req-build-bgue1v76\\setup.py'"'"';f=getattr(tokenize, '"'"'open'"'"', open)(__file__);code=f.read().replace('"'"'\r\n'"'"', '"'"'\n'"'"');f.close();exec(compile(code, __file__, '"'"'exec'"'"'))' install --record 'C:\Users\vincluff\AppData\Local\Temp\pip-record-lcx9op7p\install-record.txt' --single-version-externally-managed --compile --install-headers 'c:\program files\python39\Include\pythonnet'
cwd: C:\Users\vincluff\AppData\Local\Temp\pip-req-build-bgue1v76\
Complete output (6 lines):
usage: setup.py [global_opts] cmd1 [cmd1_opts] [cmd2 [cmd2_opts] ...]
or: setup.py --help [cmd1 cmd2 ...]
or: setup.py --help-commands
or: setup.py cmd --help
error: option --single-version-externally-managed not recognized
----------------------------------------
ERROR: Command errored out with exit status 1: 'c:\program files\python39\python.exe' -u -c 'import sys, setuptools, tokenize; sys.argv[0] = '"'"'C:\\Users\\vincluff\\AppData\\Local\\Temp\\pip-req-build-bgue1v76\\setup.py'"'"'; __file__='"'"'C:\\Users\\vincluff\\AppData\\Local\\Temp\\pip-req-build-bgue1v76\\setup.py'"'"';f=getattr(tokenize, '"'"'open'"'"', open)(__file__);code=f.read().replace('"'"'\r\n'"'"', '"'"'\n'"'"');f.close();exec(compile(code, __file__, '"'"'exec'"'"'))' install --record 'C:\Users\vincluff\AppData\Local\Temp\pip-record-lcx9op7p\install-record.txt' --single-version-externally-managed --compile --install-headers 'c:\program files\python39\Include\pythonnet' Check the logs for full command output
- Why do the above steps fail?
- If I get this working, will it allow the creation of a Python.Net wheel which matches the installed Python version?
Note: I was able to get offline install working with the following steps but this is using a wheel that is specific to my installed version of Python. I want it to work with whatever Python version the customer has.
pip install pythonnet
< search in C:\Users\vince\AppData\Local\pip\cache\wheels for pythonnet-2.5.2-cp39-cp39-win_amd64.whl and copy it to C:\copy_of_pythonnet_wheel >
pip uninstall pythonnet
pip install C:\copy_of_pythonnet_wheel\pythonnet-2.5.2-cp39-cp39-win_amd64.whl
Related question about Python.Runtime.dll:
If I go with an online installer (pip install pythonnet), it places Python.Runtime.dll in the site-packages directory, e.g: C:\Program Files\Python39\Lib\site-packages. Should my .Net application load this Python.Runtime.dll, or should it use the Python.Runtime.dll that I compiled my .Net project against, and so is already installed in C:\Program Files\MyDotNetExeLocation ?
If the former, how do I specify the location of Python.Runtime.dll? The location depends on where the user decides to install Python so I don’t know where to find it. One solution I can think of: After my installer has installed Python.Net, it checks location of site-packages using:
py.exe -c "import site; print(next(item for item in site.getsitepackages() if 'site-packages' in item))"
And then copies Python.Runtime.dll from this directory into C:\Program Files\MyDotNetExeLocation