21

When I attempt to run the Python interpretter within lldb, I'm seeing:

$ lldb
(lldb) script
Traceback (most recent call last):
  File "<input>", line 1, in <module>
  File "/usr/local/Cellar/python/2.7.14/Frameworks/Python.framework/Versions/2.7/lib/python2.7/copy.py", line 52, in <module>
    import weakref
  File "/usr/local/Cellar/python/2.7.14/Frameworks/Python.framework/Versions/2.7/lib/python2.7/weakref.py", line 14, in <module>
    from _weakref import (
ImportError: cannot import name _remove_dead_weakref
Python Interactive Interpreter. To exit, type 'quit()', 'exit()' or Ctrl-D.

When I inspect what version of Python was launched, Python reports that it should be the Homebrew Python (which is symlinked into this location):

>>> sys.executable
'/usr/local/opt/python/bin/python2.7'

However, asking the Python version returns the version associated with the default system Python installation, e.g.

>>> sys.version_info
sys.version_info(major=2, minor=7, micro=10, releaselevel='final', serial=0)

And, just to confirm, the Python version at the binary path above is indeed different (note the difference in the micro version):

$ /usr/local/opt/python/bin/python2.7 --version
Python 2.7.14

$ /usr/bin/python --version
Python 2.7.10

To make things more confusing, the name _remove_dead_weakref does exist in the _weakref module for my Homebrew Python installation, but not the default system installation:

$ /usr/bin/python -c "import _weakref; print _weakref._remove_dead_weakref"
Traceback (most recent call last):
  File "<string>", line 1, in <module>
AttributeError: 'module' object has no attribute '_remove_dead_weakref'

$ /usr/local/opt/python/bin/python2.7 -c "import _weakref; print _weakref._remove_dead_weakref"
<built-in function _remove_dead_weakref>

Any idea what could be causing this apparent cross-talk between my Python installations with LLDB? How can I prevent this?

Kevin Ushey
  • 20,530
  • 5
  • 56
  • 88

4 Answers4

16

One workaround to this issue is to explicitly launch LLDB with only the system Python installation on the PATH, e.g.

PATH=/usr/bin /usr/bin/lldb

It appears as though LLDB queries the PATH for the 'active' Python installation; if you have a Homebrew installation of Python available on the PATH then you can run into this sort of cross-talk when LLDB attempts to launch Python.

Kevin Ushey
  • 20,530
  • 5
  • 56
  • 88
  • 1
    I looked through the lldb sources to see where we might be doing that, and I can't find anywhere where we initialize python specially. This might be going on under the hood in Python? It is all done here: http://llvm.org/svn/llvm-project/lldb/trunk/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp in InitializePythonRAII if there are any Python experts out there that want to have a look to see if we're doing this wrong. – Jim Ingham Dec 06 '17 at 01:39
  • 1
    @JimIngham LLDB.framework links against the system Python.framework so it's already bound to the system Python. it should probably either only use the system Python, or be flexible enough in loading the framework from elsewhere. – rgov Jul 10 '18 at 15:04
  • 2
    for me, `brew unlink python@2` seems to work as well. I don't need the homebrew "python" executable in my PATH. – Johannes Bittner Jan 27 '19 at 00:56
7

If we run lldb with DYLD_PRINT_LIBRARIES=1 set, then we can see that it's loading the Python.framework from /System/Library, but then some other Python libraries from Homebrew:

dyld: loaded: /System/Library/Frameworks/Python.framework/Versions/2.7/Python
...
dyld: loaded: /usr/local/Cellar/python@2/2.7.15_1/Frameworks/Python.framework/Versions/2.7/lib/python2.7/lib-dynload/_locale.so

But if we tell DYLD to specifically load Python.framework from Homebrew, then it works:

DYLD_FRAMEWORK_PATH="$(brew --prefix python@2)/Frameworks/" "$(xcrun -f lldb)"

Tested on macOS 10.13.6 with brew'd Python 2.7.15.

Update: When System Integrity Protection is enabled, using DYLD_FRAMEWORK_PATH may be prohibited on the Xcode Command Line Tools trampoline executables running from /usr/bin. To work around that, we run xcrun -f lldb to use the real LLDB executable instead.

rgov
  • 3,516
  • 1
  • 31
  • 51
  • Yes. Indeed for {,ba,z}sh. Updated. –  Jan 03 '19 at 16:03
  • 1
    Intriguing. Using **MacPorts**, though I don't think one can be so fancy as selecting certain version inline (wh/as what's `ln`'d in `/opt/local`'d be done w/ `port select`), I could run mine w/o errs in `script`: `DYLD_FRAMEWORK_PATH=/opt/local/Library/Frameworks lldb` – vike May 03 '19 at 10:27
  • `DYLD_FRAMEWORK_PATH="$(brew --prefix python@2)/Frameworks/" lldb` doesn't work for me on macOS 10.14.6 with brew'd Python 2.7.16. Whether or not I set `DYLD_FRAMEWORK_PATH` I get the same paths in the error (`/usr/local/Cellar/python@2/2.7.16/Frameworks/Python.framework/Versions/2.7/lib/python2.7/copy.py`). Even if I instead do `DYLD_FRAMEWORK_PATH="$(brew --prefix python)/Frameworks/" lldb` and try to use Python3 instead, it will still try to use Python 2 with the same paths as before – Max Coplan Sep 03 '19 at 15:11
  • I think this may have to do with SIP purging all environment variables sent to dyld [source](https://stackoverflow.com/a/33589760/6100005) – Max Coplan Sep 03 '19 at 15:23
  • Indeed, running `DYLD_FRAMEWORK_PATH="$(brew --prefix python@2)/Frameworks/" /Applications/Xcode.app/Contents/Developer/usr/bin/lldb` fixes the issue – Max Coplan Sep 03 '19 at 15:27
  • Follow up question: when running the above and checking `sys.executable`, I get `'/Applications/Xcode.app/Contents/Developer/usr/bin/lldb'`. If I instead set the framework path to just `python` (instead of `python@2`) (to try and get python3), the error returns and `sys.executable` is `'/usr/local/opt/python@2/bin/python2.7'`. How can I get python 3 in lldb? – Max Coplan Sep 03 '19 at 15:31
  • @MaxCoplan I updated my answer, thanks for pointing out SIP problems. I'm not sure about Python3. Please post a new question and link to it here. – rgov Sep 04 '19 at 17:22
4

You can simply run brew unlink python@2 instead of uninstalling it. This will remove Homebrew's Python 2.x from your PATH. A lot of Homebrew formulas depend on Homebrew's Python 2.x, so you can keep the brew-installed Python 2.x while also fixing the error with lldb.

If you manage your Homebrew setup with Homebrew Bundle, you can add this line to your Brewfile:

brew "python@2", link: false
rootbeersoup
  • 143
  • 3
  • 6
0

I've solved this problem with uninstalling python@2 from Homebrew: https://github.com/flutter/flutter/issues/17803#issuecomment-390980648

UPD:

As @Olsonist noted in comments, running this command must fix this problem: brew uninstall --force python@2

maksadbek
  • 1,508
  • 2
  • 15
  • 28