summaryrefslogtreecommitdiff
path: root/src/virtualenv/create
diff options
context:
space:
mode:
authorBernát Gábor <bgabor8@bloomberg.net>2020-03-13 16:27:05 +0000
committerGitHub <noreply@github.com>2020-03-13 16:27:05 +0000
commit3816e7c7881bdc9ca99e18fe69810c856c9a9d2d (patch)
treef23362cf0188a57fa271a9e8db583962c07fffbf /src/virtualenv/create
parent06f8cd124d2b3680283f66f942a7d008fedfe599 (diff)
downloadvirtualenv-3816e7c7881bdc9ca99e18fe69810c856c9a9d2d.tar.gz
macOS Python 3 Framework support (#1711)
Signed-off-by: Bernat Gabor <bgabor8@bloomberg.net>
Diffstat (limited to 'src/virtualenv/create')
-rw-r--r--src/virtualenv/create/via_global_ref/builtin/cpython/common.py8
-rw-r--r--src/virtualenv/create/via_global_ref/builtin/cpython/cpython2.py7
-rw-r--r--src/virtualenv/create/via_global_ref/builtin/cpython/cpython3.py6
-rw-r--r--src/virtualenv/create/via_global_ref/builtin/cpython/mac_os.py104
4 files changed, 94 insertions, 31 deletions
diff --git a/src/virtualenv/create/via_global_ref/builtin/cpython/common.py b/src/virtualenv/create/via_global_ref/builtin/cpython/common.py
index 814d97e..ac251b9 100644
--- a/src/virtualenv/create/via_global_ref/builtin/cpython/common.py
+++ b/src/virtualenv/create/via_global_ref/builtin/cpython/common.py
@@ -46,3 +46,11 @@ class CPythonWindows(CPython, WindowsSupports):
# for more info on pythonw.exe see https://stackoverflow.com/a/30313091
python_w = host.parent / "pythonw.exe"
yield python_w, [python_w.name]
+
+
+def is_mac_os_framework(interpreter):
+ if interpreter.platform == "darwin":
+ framework_var = interpreter.sysconfig_vars.get("PYTHONFRAMEWORK")
+ value = "Python3" if interpreter.version_info.major == 3 else "Python"
+ return framework_var == value
+ return False
diff --git a/src/virtualenv/create/via_global_ref/builtin/cpython/cpython2.py b/src/virtualenv/create/via_global_ref/builtin/cpython/cpython2.py
index 4e20f4a..c46a95e 100644
--- a/src/virtualenv/create/via_global_ref/builtin/cpython/cpython2.py
+++ b/src/virtualenv/create/via_global_ref/builtin/cpython/cpython2.py
@@ -9,7 +9,7 @@ from virtualenv.create.via_global_ref.builtin.ref import PathRefToDest
from virtualenv.util.path import Path
from ..python2.python2 import Python2
-from .common import CPython, CPythonPosix, CPythonWindows
+from .common import CPython, CPythonPosix, CPythonWindows, is_mac_os_framework
@add_metaclass(abc.ABCMeta)
@@ -50,11 +50,6 @@ class CPython2(CPython, Python2):
return dirs
-def is_mac_os_framework(interpreter):
- framework = bool(interpreter.sysconfig_vars.get("PYTHONFRAMEWORK"))
- return framework and interpreter.platform == "darwin"
-
-
class CPython2Posix(CPython2, CPythonPosix):
"""CPython 2 on POSIX (excluding macOs framework builds)"""
diff --git a/src/virtualenv/create/via_global_ref/builtin/cpython/cpython3.py b/src/virtualenv/create/via_global_ref/builtin/cpython/cpython3.py
index a6639c2..5571520 100644
--- a/src/virtualenv/create/via_global_ref/builtin/cpython/cpython3.py
+++ b/src/virtualenv/create/via_global_ref/builtin/cpython/cpython3.py
@@ -8,7 +8,7 @@ from virtualenv.create.describe import Python3Supports
from virtualenv.create.via_global_ref.builtin.ref import PathRefToDest
from virtualenv.util.path import Path
-from .common import CPython, CPythonPosix, CPythonWindows
+from .common import CPython, CPythonPosix, CPythonWindows, is_mac_os_framework
@add_metaclass(abc.ABCMeta)
@@ -17,7 +17,9 @@ class CPython3(CPython, Python3Supports):
class CPython3Posix(CPythonPosix, CPython3):
- """"""
+ @classmethod
+ def can_describe(cls, interpreter):
+ return is_mac_os_framework(interpreter) is False and super(CPython3Posix, cls).can_describe(interpreter)
class CPython3Windows(CPythonWindows, CPython3):
diff --git a/src/virtualenv/create/via_global_ref/builtin/cpython/mac_os.py b/src/virtualenv/create/via_global_ref/builtin/cpython/mac_os.py
index 7c2cb93..fd7f0e3 100644
--- a/src/virtualenv/create/via_global_ref/builtin/cpython/mac_os.py
+++ b/src/virtualenv/create/via_global_ref/builtin/cpython/mac_os.py
@@ -4,51 +4,82 @@ import logging
import os
import struct
import subprocess
+from abc import ABCMeta, abstractmethod
from textwrap import dedent
-from virtualenv.create.via_global_ref.builtin.cpython.common import CPythonPosix
-from virtualenv.create.via_global_ref.builtin.ref import PathRefToDest
+from six import add_metaclass
+
+from virtualenv.create.via_global_ref.builtin.ref import ExePathRefToDest, PathRefToDest
from virtualenv.util.path import Path
from virtualenv.util.six import ensure_text
-from .cpython2 import CPython2, is_mac_os_framework
+from .common import CPython, CPythonPosix, is_mac_os_framework
+from .cpython2 import CPython2
+from .cpython3 import CPython3
-class CPython2macOsFramework(CPython2, CPythonPosix):
+@add_metaclass(ABCMeta)
+class CPythonmacOsFramework(CPython):
@classmethod
def can_describe(cls, interpreter):
- return is_mac_os_framework(interpreter) and super(CPython2macOsFramework, cls).can_describe(interpreter)
-
- def create(self):
- super(CPython2macOsFramework, self).create()
-
- # change the install_name of the copied python executable
- current = os.path.join(self.interpreter.prefix, "Python")
- fix_mach_o(str(self.exe), current, "@executable_path/../.Python", self.interpreter.max_size)
+ return is_mac_os_framework(interpreter) and super(CPythonmacOsFramework, cls).can_describe(interpreter)
@classmethod
def sources(cls, interpreter):
- for src in super(CPython2macOsFramework, cls).sources(interpreter):
+ for src in super(CPythonmacOsFramework, cls).sources(interpreter):
yield src
-
- # landmark for exec_prefix
- name = "lib-dynload"
- yield PathRefToDest(interpreter.stdlib_path(name), dest=cls.to_stdlib)
-
- # this must symlink to the host prefix Python
- marker = Path(interpreter.prefix) / "Python"
- ref = PathRefToDest(marker, dest=lambda self, _: self.dest / ".Python", must_symlink=True)
+ # add a symlink to the host python image
+ ref = PathRefToDest(cls.image_ref(interpreter), dest=lambda self, _: self.dest / ".Python", must_symlink=True)
yield ref
+ def create(self):
+ super(CPythonmacOsFramework, self).create()
+
+ # change the install_name of the copied python executables
+ target = "@executable_path/../.Python"
+ current = self.current_mach_o_image_path()
+ for src in self._sources:
+ if isinstance(src, ExePathRefToDest):
+ if src.must_copy or not self.symlinks:
+ exes = [self.bin_dir / src.base]
+ if not self.symlinks:
+ exes.extend(self.bin_dir / a for a in src.aliases)
+ for exe in exes:
+ fix_mach_o(str(exe), current, target, self.interpreter.max_size)
+
@classmethod
def _executables(cls, interpreter):
- for _, targets in super(CPython2macOsFramework, cls)._executables(interpreter):
+ for _, targets in super(CPythonmacOsFramework, cls)._executables(interpreter):
# Make sure we use the embedded interpreter inside the framework, even if sys.executable points to the
# stub executable in ${sys.prefix}/bin.
# See http://groups.google.com/group/python-virtualenv/browse_thread/thread/17cab2f85da75951
fixed_host_exe = Path(interpreter.prefix) / "Resources" / "Python.app" / "Contents" / "MacOS" / "Python"
yield fixed_host_exe, targets
+ @abstractmethod
+ def current_mach_o_image_path(self):
+ raise NotImplementedError
+
+ @classmethod
+ def image_ref(cls, interpreter):
+ raise NotImplementedError
+
+
+class CPython2macOsFramework(CPythonmacOsFramework, CPython2, CPythonPosix):
+ @classmethod
+ def image_ref(cls, interpreter):
+ return Path(interpreter.prefix) / "Python"
+
+ def current_mach_o_image_path(self):
+ return os.path.join(self.interpreter.prefix, "Python")
+
+ @classmethod
+ def sources(cls, interpreter):
+ for src in super(CPython2macOsFramework, cls).sources(interpreter):
+ yield src
+ name = "lib-dynload" # landmark for exec_prefix
+ yield PathRefToDest(interpreter.stdlib_path(name), dest=cls.to_stdlib)
+
@property
def reload_code(self):
result = super(CPython2macOsFramework, self).reload_code
@@ -56,7 +87,6 @@ class CPython2macOsFramework(CPython2, CPythonPosix):
"""
# the bundled site.py always adds the global site package if we're on python framework build, escape this
import sysconfig
-
config = sysconfig.get_config_vars()
before = config["PYTHONFRAMEWORK"]
try:
@@ -71,6 +101,34 @@ class CPython2macOsFramework(CPython2, CPythonPosix):
return result
+class CPython3macOsFramework(CPythonmacOsFramework, CPython3, CPythonPosix):
+ @classmethod
+ def image_ref(cls, interpreter):
+ return Path(interpreter.prefix) / "Python3"
+
+ def current_mach_o_image_path(self):
+ return "@executable_path/../../../../Python3"
+
+ @property
+ def reload_code(self):
+ result = super(CPython3macOsFramework, self).reload_code
+ result = dedent(
+ """
+ # the bundled site.py always adds the global site package if we're on python framework build, escape this
+ import sys
+ before = sys._framework
+ try:
+ sys._framework = None
+ {}
+ finally:
+ sys._framework = before
+ """.format(
+ result
+ )
+ )
+ return result
+
+
def fix_mach_o(exe, current, new, max_size):
"""
https://en.wikipedia.org/wiki/Mach-O