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

fix pypy2 builtins are imported as stdlib modules #1656

Merged
merged 2 commits into from
Feb 23, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions docs/changelog/1652.bugfix.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Fix PyPy 2 builtin modules are imported from standard library, rather than from builtin - by :user:`gaborbernat`.
9 changes: 9 additions & 0 deletions src/virtualenv/create/via_global_ref/builtin/pypy/pypy2.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import abc
import logging
import os

from six import add_metaclass

Expand Down Expand Up @@ -65,6 +66,14 @@ def ensure_directories(self):
logging.debug("no include folders as can't find include marker %s", host_include_marker)
return dirs

@property
def skip_rewrite(self):
"""
PyPy2 built-in imports are handled by this path entry, don't overwrite to not disable it
see: https://github.com/pypa/virtualenv/issues/1652
"""
return 'or value.endswith("lib_pypy{}__extensions__")'.format(os.sep)


class PyPy2Posix(PyPy2, PosixSupports):
"""PyPy 2 on POSIX"""
Expand Down
15 changes: 12 additions & 3 deletions src/virtualenv/create/via_global_ref/builtin/python2/python2.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,16 +32,25 @@ def create(self):
else:
custom_site_text = custom_site.read_text()
expected = json.dumps([os.path.relpath(ensure_text(str(i)), ensure_text(str(site_py))) for i in self.libs])

custom_site_text = custom_site_text.replace("___EXPECTED_SITE_PACKAGES___", expected)
custom_site_text = custom_site_text.replace(
"# ___RELOAD_CODE___", os.linesep.join(" {}".format(i) for i in self.reload_code.splitlines()).lstrip()
)

reload_code = os.linesep.join(" {}".format(i) for i in self.reload_code.splitlines()).lstrip()
custom_site_text = custom_site_text.replace("# ___RELOAD_CODE___", reload_code)

skip_rewrite = os.linesep.join(" {}".format(i) for i in self.skip_rewrite.splitlines()).lstrip()
custom_site_text = custom_site_text.replace("# ___SKIP_REWRITE____", skip_rewrite)

site_py.write_text(custom_site_text)

@property
def reload_code(self):
return 'reload(sys.modules["site"]) # noqa # call system site.py to setup import libraries'

@property
def skip_rewrite(self):
return ""

@classmethod
def sources(cls, interpreter):
for src in super(Python2, cls).sources(interpreter):
Expand Down
21 changes: 11 additions & 10 deletions src/virtualenv/create/via_global_ref/builtin/python2/site.py
Original file line number Diff line number Diff line change
Expand Up @@ -86,16 +86,17 @@ def rewrite_standard_library_sys_path():
for at, value in enumerate(sys.path):
value = abs_path(value)
# replace old sys prefix path starts with new
if value == exe_dir:
pass # don't fix the current executable location, notably on Windows this gets added
elif value.startswith(exe_dir):
# content inside the exe folder needs to remap to original executables folder
orig_exe_folder = base_executable[: base_executable.rfind(sep)]
value = "{}{}".format(orig_exe_folder, value[len(exe_dir) :])
elif value.startswith(prefix):
value = "{}{}".format(base_prefix, value[len(prefix) :])
elif value.startswith(exec_prefix):
value = "{}{}".format(base_exec_prefix, value[len(exec_prefix) :])
skip_rewrite = value == exe_dir # don't fix the current executable location, notably on Windows this gets added
skip_rewrite = skip_rewrite # ___SKIP_REWRITE____
if not skip_rewrite:
if value.startswith(exe_dir):
# content inside the exe folder needs to remap to original executables folder
orig_exe_folder = base_executable[: base_executable.rfind(sep)]
value = "{}{}".format(orig_exe_folder, value[len(exe_dir) :])
elif value.startswith(prefix):
value = "{}{}".format(base_prefix, value[len(prefix) :])
elif value.startswith(exec_prefix):
value = "{}{}".format(base_exec_prefix, value[len(exec_prefix) :])
sys.path[at] = value


Expand Down
23 changes: 16 additions & 7 deletions src/virtualenv/seed/via_app_data/pip_install/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
import os
import re
import shutil
import sys
import zipfile
from abc import ABCMeta, abstractmethod
from contextlib import contextmanager
Expand Down Expand Up @@ -135,28 +134,38 @@ def _create_console_entry_point(self, name, value, to_folder, version_info):

maker = ScriptMaker(None, str(to_folder))
maker.clobber = True # overwrite
maker.variants = {"", "X", "X.Y"} # create all variants
maker.variants = {""}
maker.set_mode = True # ensure they are executable
maker.executable = str(self._creator.exe)
specification = "{} = {}".format(name, value)
with self.switch_sys_version(version_info):
with self.patch_distlib_correct_variants(version_info, maker):
new_files = maker.make(specification)
result.extend(Path(i) for i in new_files)
return result

@contextmanager
def switch_sys_version(self, version_info):
def patch_distlib_correct_variants(self, version_info, maker):
"""
Patch until upstream distutils supports creating scripts with different python target
https://bitbucket.org/pypa/distlib/issues/134/allow-specifying-the-version-information
"""
previous = sys.version_info

def _write_script(scriptnames, shebang, script, filenames, ext):
name = next(iter(scriptnames))
scriptnames = { # add our variants '', 'X', '-X.Y'
name,
"{}{}".format(name, version_info.major),
"{}-{}.{}".format(name, version_info.major, version_info.minor),
}
return previous(scriptnames, shebang, script, filenames, ext)

previous = maker._write_script
with self.lock:
sys.version_info = version_info
maker._write_script = _write_script
try:
yield
finally:
sys.version_info = previous
maker._write_script = previous

def clear(self):
if self._image_dir.exists():
Expand Down