Repository: pypa/virtualenv

Issue:
install_name_tool feature merge causes errors with Python 3
This was originally a comment on pull request #289. @carljm asked me to file a separate bug for it.

I just ran into a problem using virtualenv 1.7.2 / Mac OS 10.7 that appears to be related to this change.

When trying to create a new Python 3 virtualenv, I got the following errors. This does not happen when I create a Python 2.7 virtualenv.

virtualenv asdf -p /usr/local/bin/python3
Running virtualenv with interpreter /usr/local/bin/python3
New python executable in asdf/bin/python
Could not call mach_o_change: expected an object with the buffer interface. Trying to call install_name_tool instead.
install_name_tool: for architecture i386 object: asdf/bin/python malformed object (unknown load command 4)
Could not call install_name_tool -- you must have Apple's development tools installed
Traceback (most recent call last):
File "/Library/Python/2.7/site-packages/virtualenv.py", line 1365, in install_python
'@executable_path/../.Python')
File "/Library/Python/2.7/site-packages/virtualenv.py", line 2425, in mach_o_change
do_file(open(path, 'r+b'))
File "/Library/Python/2.7/site-packages/virtualenv.py", line 2414, in do_file
do_file(file, offset, size)
File "/Library/Python/2.7/site-packages/virtualenv.py", line 2418, in do_file
do_macho(file, 32, LITTLE_ENDIAN)
File "/Library/Python/2.7/site-packages/virtualenv.py", line 2396, in do_macho
load = load[:load.index('\0')]
TypeError: expected an object with the buffer interface

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
File "/Library/Python/2.7/site-packages/virtualenv.py", line 2429, in 
main()
File "/Library/Python/2.7/site-packages/virtualenv.py", line 942, in main
never_download=options.never_download)
File "/Library/Python/2.7/site-packages/virtualenv.py", line 1043, in create_environment
site_packages=site_packages, clear=clear))
File "/Library/Python/2.7/site-packages/virtualenv.py", line 1375, in install_python
py_executable])
File "/Library/Python/2.7/site-packages/virtualenv.py", line 1020, in call_subprocess
% (cmd_desc, proc.returncode))
OSError: Command install_name_tool -change /Library/Frameworks/.../Versions/3.2/Python @executable_path/../.Python asdf/bin/python failed with error code 1

Not 100% sure this isn't caused by something that is my own fault (I may have broken my Apple developer tools trying & failing to upgrade Ruby a couple of weeks ago, or I may have installed Python 3 incorrectly on this system just now), but I figured I should report it. Feel free to delete/move this.



Discussion:
Trying to replicate.

```
Running virtualenv with interpreter /usr/local/bin/python3
New python executable in asdf/bin/python
Could not call mach_o_change: Type str doesn't support the buffer API. Trying to call install_name_tool instead.
Installing distribute...................................................................................................................................................................................................................................................................................................................................................................done.
```


Resolving patch:
diff --git a/virtualenv.py b/virtualenv.py
--- a/virtualenv.py
+++ b/virtualenv.py
@@ -2404,12 +2404,12 @@ def do_macho(file, bits, endian):
                 name_offset = read_data(file, endian)
                 file.seek(where + name_offset, os.SEEK_SET)
                 # Read the NUL terminated string
-                load = file.read(cmdsize - name_offset)
+                load = file.read(cmdsize - name_offset).decode()
                 load = load[:load.index('\0')]
                 # If the string is what is being replaced, overwrite it.
                 if load == what:
                     file.seek(where + name_offset, os.SEEK_SET)
-                    file.write(value + '\0')
+                    file.write(value.encode() + '\0'.encode())
             # Seek to the next command
             file.seek(where + cmdsize, os.SEEK_SET)
 


Test patch: