Skip to content
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

Using link to execute relocated 3.11 bin/python3 fails to find libraries #31

Open
MagerValp opened this issue Feb 24, 2023 · 6 comments

Comments

@MagerValp
Copy link

MagerValp commented Feb 24, 2023

We're using a symbolic link for munkireport-python3 to point to a relocated python framework:

 → ls -l /usr/local/munkireport/munkireport-python3 
lrwxr-xr-x  1 root  wheel  63 24 Feb 10:10 /usr/local/munkireport/munkireport-python3 -> /Library/MunkiReport/Python.framework/Versions/3.11/bin/python3

Executing /Library/MunkiReport/Python.framework/Versions/3.11/bin/python3 works fine:

 → /Library/MunkiReport/Python.framework/Versions/3.11/bin/python3
Python 3.11.2 (v3.11.2:878ead1ac1, Feb  7 2023, 10:02:41) [Clang 13.0.0 (clang-1300.0.29.30)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import sys
>>> sys.path
['',
 '/Library/MunkiReport/Python.framework/Versions/3.11/lib/python311.zip',
 '/Library/MunkiReport/Python.framework/Versions/3.11/lib/python3.11',
 '/Library/MunkiReport/Python.framework/Versions/3.11/lib/python3.11/lib-dynload',
 '/Library/MunkiReport/Python.framework/Versions/3.11/lib/python3.11/site-packages']
>>> ^D

Calling it with the link fails to find platform dependent libraries:

 → /usr/local/munkireport/munkireport-python3 
Could not find platform dependent libraries <exec_prefix>
Python 3.11.2 (v3.11.2:878ead1ac1, Feb  7 2023, 10:02:41) [Clang 13.0.0 (clang-1300.0.29.30)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import sys
>>> sys.path
['',
 '/Library/MunkiReport/Python.framework/Versions/3.11/lib/python311.zip',
 '/Library/MunkiReport/Python.framework/Versions/3.11/lib/python3.11',
 '/Library/Frameworks/Python.framework/Versions/3.11/lib/python3.11/lib-dynload',        # ouch
 '/Library/MunkiReport/Python.framework/Versions/3.11/lib/python3.11/site-packages']
>>> import socket
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/Library/MunkiReport/Python.framework/Versions/3.11/lib/python3.11/socket.py", line 51, in <module>
    import _socket
ModuleNotFoundError: No module named '_socket'
>>> ^D

A relocated 3.10 doesn't seem to have a problem with this:

 → /usr/local/munkireport/munkireport-python3                     
Python 3.10.2 (v3.10.2:a58ebcc701, Jan 13 2022, 14:50:16) [Clang 13.0.0 (clang-1300.0.29.30)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import sys
>>> sys.path
['',
 '/Library/MunkiReport/Python.framework/Versions/3.10/lib/python310.zip',
 '/Library/MunkiReport/Python.framework/Versions/3.10/lib/python3.10',
 '/Library/MunkiReport/Python.framework/Versions/3.10/lib/python3.10/lib-dynload',
 '/Library/MunkiReport/Python.framework/Versions/3.10/lib/python3.10/site-packages']
>>> ^D

I'm building with these options:

	./make_relocatable_python_framework.py \
		--upgrade-pip \
		--pip-requirements="../$PKGDIR/requirements.txt" \
		--os-version=11 \
		--python-version "$version" \
		--destination "../$FWROOT" \
@MagerValp
Copy link
Author

I suspect that this is the relevant upstream change: python/cpython#29041

@gregneagle
Copy link
Owner

Possible workaround would be to replace the symlink with a shell script that basically does

/real/path/to/Python.framework/Versions/Current/bin/python3 $additional_args

@carlashley
Copy link

carlashley commented May 31, 2023

I've been playing around with PYTHONPATH and PYTHONHOME as documented here which "works", but keep in mind that thse exported environment vars will apply to any other installations of Python on the system (obviously depending on how/where they're exported).
Also, any PYTHONPATH exports are added to the existing path that Python itself generates, so you could end up with a precedence issue as the exported PYTHONPATH may take priority in search order, etc, so it could have unintended consequences for any possible clashing imports.

Without the exports, you get the Could not find platform dependent libraries <exec_prefix> error and can't import standard packages like subprocess, etc.

[appleseed@infiniteloop]:~ # export PYTHONPATH=""                                                                                  
[appleseed@infiniteloop]:~ # export PYTHONHOME=""
[appleseed@infiniteloop]:~ # python3             
Could not find platform dependent libraries <exec_prefix>
Python 3.11.3 (v3.11.3:f3909b8bc8, Apr  4 2023, 20:12:10) [Clang 13.0.0 (clang-1300.0.29.30)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import sys, subprocess
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/Library/ManagedFrameworks/Python.framework/Versions/3.11/lib/python3.11/subprocess.py", line 104, in <module>
    from _posixsubprocess import fork_exec as _fork_exec
ModuleNotFoundError: No module named '_posixsubprocess'
>>> import pprint
>>> pprint.pprint(sys.path)
['',
 '/Library/ManagedFrameworks/Python.framework/Versions/3.11/lib/python311.zip',
 '/Library/ManagedFrameworks/Python.framework/Versions/3.11/lib/python3.11',
 '/Library/Frameworks/Python.framework/Versions/3.11/lib/python3.11/lib-dynload',
 '/Library/ManagedFrameworks/Python.framework/Versions/3.11/lib/python3.11/site-packages',
 '/usr/local/python/site-packages']
>>> 

With the exports, the Could not find platform dependent libraries <exec_prefix> error is gone, and can now import standard packages like subprocess, etc.

[appleseed@infiniteloop]:~ # export PYTHONHOME=/Library/ManagedFrameworks/Python.framework/Versions/3.11
[appleseed@infiniteloop]:~ # export PYTHONPATH=/Library/ManagedFrameworks/Python.framework/Versions/3.11/lib/python3.11/lib-dynload                        
[appleseed@infiniteloop]:~ # python3                                                                                                                       
Python 3.11.3 (v3.11.3:f3909b8bc8, Apr  4 2023, 20:12:10) [Clang 13.0.0 (clang-1300.0.29.30)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import sys
>>> from pprint import pprint
>>> import subprocess
>>> pprint(sys.path)
['',
 '/Library/ManagedFrameworks/Python.framework/Versions/3.11/lib/python3.11/lib-dynload',
 '/Library/ManagedFrameworks/Python.framework/Versions/3.11/lib/python311.zip',
 '/Library/ManagedFrameworks/Python.framework/Versions/3.11/lib/python3.11',
 '/Library/Frameworks/Python.framework/Versions/3.11/lib/python3.11/lib-dynload',
 '/Library/ManagedFrameworks/Python.framework/Versions/3.11/lib/python3.11/site-packages',
 '/usr/local/python/site-packages']
>>> 
KeyboardInterrupt
>>> ^D

This is very early testing, and understandably won't work particularly well if your Python deployments are more complicated than just installing the ManagedFrameworks version, or in the case of munki, so YMMV.

@nmcspadden
Copy link
Contributor

With @carlashley's tip, I was able to work around this by creating a simple shim script that can be invoked (the context here was addressing macadmins/python#48):

#!/bin/zsh

bin="/Library/ManagedFrameworks/Python/Python3.framework/Versions/3.11/bin/python3.11"

PYTHONHOME=/Library/ManagedFrameworks/Python.framework/Versions/3.11
PYTHONPATH=/Library/ManagedFrameworks/Python.framework/Versions/3.11/lib/python3.11/lib-dynload
exec "${bin}" "$@"

This script can put anywhere (such as /usr/local/bin/managed_python or whatever), and solves the immediate issue:

% /usr/local/bin/managed_python3_fixed
Python 3.11.1 (v3.11.1:a7a450f84a, Dec  6 2022, 15:24:06) [Clang 13.0.0 (clang-1300.0.29.30)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import requests
>>> exit()

@nmcspadden
Copy link
Contributor

Actually, this works even without the two env variables.

I used Munki's build_python_framework.sh script to build a 3.12.2 Python framework (see munki/munki#1204 for why), and inserted this shell script:

% cat /usr/local/munki/python3.12.fixed
#!/bin/sh
# Wrapper to force arm64 execution of the python3.12 universal binary; the `arch` is probably unnecessary
exec /usr/bin/arch -arm64 /Users/nmcspadden/Documents/GitHub/munki/Python.framework/Versions/3.12/bin/python3 "$@"

Then:

% /usr/local/munki/python3.12.fixed
Python 3.12.2 (v3.12.2:6abddd9f6a, Feb  6 2024, 17:02:06) [Clang 13.0.0 (clang-1300.0.29.30)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import sys
>>> sys.path
['', '/Users/nmcspadden/Documents/GitHub/munki/Python.framework/Versions/3.12/lib/python312.zip', '/Users/nmcspadden/Documents/GitHub/munki/Python.framework/Versions/3.12/lib/python3.12', '/Users/nmcspadden/Documents/GitHub/munki/Python.framework/Versions/3.12/lib/python3.12/lib-dynload', '/Users/nmcspadden/Documents/GitHub/munki/Python.framework/Versions/3.12/lib/python3.12/site-packages']
>>> import socket
>>> 

It seems to correctly utilize the path of the directory it's in, rather than looking in /Library/Frameworks.

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

No branches or pull requests

4 participants