1from __future__ import absolute_import, unicode_literals 2 3import abc 4import logging 5 6from six import add_metaclass 7 8from virtualenv.create.via_global_ref.builtin.ref import PathRefToDest 9from virtualenv.util.path import Path 10 11from ..python2.python2 import Python2 12from .common import CPython, CPythonPosix, CPythonWindows, is_mac_os_framework 13 14 15@add_metaclass(abc.ABCMeta) 16class CPython2(CPython, Python2): 17 """Create a CPython version 2 virtual environment""" 18 19 @classmethod 20 def sources(cls, interpreter): 21 for src in super(CPython2, cls).sources(interpreter): 22 yield src 23 # include folder needed on Python 2 as we don't have pyenv.cfg 24 host_include_marker = cls.host_include_marker(interpreter) 25 if host_include_marker.exists(): 26 yield PathRefToDest(host_include_marker.parent, dest=lambda self, _: self.include) 27 28 @classmethod 29 def needs_stdlib_py_module(cls): 30 return False 31 32 @classmethod 33 def host_include_marker(cls, interpreter): 34 return Path(interpreter.system_include) / "Python.h" 35 36 @property 37 def include(self): 38 # the pattern include the distribution name too at the end, remove that via the parent call 39 return (self.dest / self.interpreter.install_path("headers")).parent 40 41 @classmethod 42 def modules(cls): 43 return [ 44 "os", # landmark to set sys.prefix 45 ] 46 47 def ensure_directories(self): 48 dirs = super(CPython2, self).ensure_directories() 49 host_include_marker = self.host_include_marker(self.interpreter) 50 if host_include_marker.exists(): 51 dirs.add(self.include.parent) 52 else: 53 logging.debug("no include folders as can't find include marker %s", host_include_marker) 54 return dirs 55 56 57@add_metaclass(abc.ABCMeta) 58class CPython2PosixBase(CPython2, CPythonPosix): 59 """common to macOs framework builds and other posix CPython2""" 60 61 @classmethod 62 def sources(cls, interpreter): 63 for src in super(CPython2PosixBase, cls).sources(interpreter): 64 yield src 65 66 # check if the makefile exists and if so make it available under the virtual environment 67 make_file = Path(interpreter.sysconfig["makefile_filename"]) 68 if make_file.exists() and str(make_file).startswith(interpreter.prefix): 69 under_prefix = make_file.relative_to(Path(interpreter.prefix)) 70 yield PathRefToDest(make_file, dest=lambda self, s: self.dest / under_prefix) 71 72 73class CPython2Posix(CPython2PosixBase): 74 """CPython 2 on POSIX (excluding macOs framework builds)""" 75 76 @classmethod 77 def can_describe(cls, interpreter): 78 return is_mac_os_framework(interpreter) is False and super(CPython2Posix, cls).can_describe(interpreter) 79 80 @classmethod 81 def sources(cls, interpreter): 82 for src in super(CPython2Posix, cls).sources(interpreter): 83 yield src 84 # landmark for exec_prefix 85 exec_marker_file, to_path, _ = cls.from_stdlib(cls.mappings(interpreter), "lib-dynload") 86 yield PathRefToDest(exec_marker_file, dest=to_path) 87 88 89class CPython2Windows(CPython2, CPythonWindows): 90 """CPython 2 on Windows""" 91 92 @classmethod 93 def sources(cls, interpreter): 94 for src in super(CPython2Windows, cls).sources(interpreter): 95 yield src 96 py27_dll = Path(interpreter.system_executable).parent / "python27.dll" 97 if py27_dll.exists(): # this might be global in the Windows folder in which case it's alright to be missing 98 yield PathRefToDest(py27_dll, dest=cls.to_bin) 99 100 libs = Path(interpreter.system_prefix) / "libs" 101 if libs.exists(): 102 yield PathRefToDest(libs, dest=lambda self, s: self.dest / s.name) 103