Beispiel #1
0
    class EnableCoverage(object):
        _COV_FILE = Path(coverage.__file__)
        _ROOT_COV_FILES_AND_FOLDERS = [
            i for i in _COV_FILE.parents[1].iterdir()
            if i.name.startswith("coverage")
        ]

        def __init__(self, link):
            self.link = link
            self.targets = []

        def __enter__(self, creator):
            site_packages = creator.purelib
            for entry in self._ROOT_COV_FILES_AND_FOLDERS:
                target = site_packages / entry.name
                if not target.exists():
                    clean = self.link(entry, target)
                    self.targets.append((target, clean))
            return self

        def __exit__(self, exc_type, exc_val, exc_tb):
            for target, clean in self.targets:
                if target.exists():
                    clean()
            assert self._COV_FILE.exists()
Beispiel #2
0
def _mock_registry(mocker):
    from virtualenv.discovery.windows.pep514 import winreg

    loc, glob = {}, {}
    mock_value_str = (Path(__file__).parent /
                      "winreg-mock-values.py").read_text()
    six.exec_(mock_value_str, glob, loc)
    enum_collect = loc["enum_collect"]
    value_collect = loc["value_collect"]
    key_open = loc["key_open"]
    hive_open = loc["hive_open"]

    def _e(key, at):
        key_id = key.value if isinstance(key, Key) else key
        result = enum_collect[key_id][at]
        if isinstance(result, OSError):
            raise result
        return result

    mocker.patch.object(winreg, "EnumKey", side_effect=_e)

    def _v(key, value_name):
        key_id = key.value if isinstance(key, Key) else key
        result = value_collect[key_id][value_name]
        if isinstance(result, OSError):
            raise result
        return result

    mocker.patch.object(winreg, "QueryValueEx", side_effect=_v)

    class Key(object):
        def __init__(self, value):
            self.value = value

        def __enter__(self):
            return self

        def __exit__(self, exc_type, exc_val, exc_tb):
            return None

    @contextmanager
    def _o(*args):
        if len(args) == 2:
            key, value = args
            key_id = key.value if isinstance(key, Key) else key
            result = Key(
                key_open[key_id][value]
            )  # this needs to be something that can be with-ed, so let's wrap it
        elif len(args) == 4:
            result = hive_open[args]
        else:
            raise RuntimeError
        value = result.value if isinstance(result, Key) else result
        if isinstance(value, OSError):
            raise value
        yield result

    mocker.patch.object(winreg, "OpenKeyEx", side_effect=_o)
    mocker.patch("os.path.exists", return_value=True)
 def _executables(cls, interpreter):
     host_exe = Path(interpreter.system_executable)
     major, minor = interpreter.version_info.major, interpreter.version_info.minor
     targets = OrderedDict((i, None) for i in [
         "python", "python{}".format(major), "python{}.{}".format(
             major, minor), host_exe.name
     ])
     yield host_exe, list(targets.keys())
Beispiel #4
0
 def env_patch_text(self):
     """Patch the distutils package to not be derailed by its configuration files"""
     with self.app_data.ensure_extracted(
             Path(__file__).parent / "_virtualenv.py") as resolved_path:
         text = resolved_path.read_text()
         return text.replace(
             '"__SCRIPT_DIR__"',
             repr(os.path.relpath(str(self.script_dir), str(self.purelib))))
Beispiel #5
0
def zipapp(zipapp_build_env, tmp_path_factory):
    into = tmp_path_factory.mktemp("zipapp")
    path = Path(HERE).parent.parent / "tasks" / "make_zipapp.py"
    filename = into / "virtualenv.pyz"
    cmd = [zipapp_build_env, str(path), "--dest", str(filename)]
    subprocess.check_call(cmd)
    yield filename
    shutil.rmtree(str(into))
Beispiel #6
0
def _find_downloaded_wheel(distribution, version_spec, for_py_version, to_folder, out):
    for line in out.splitlines():
        line = line.lstrip()
        for marker in ("Saved ", "File was already downloaded "):
            if line.startswith(marker):
                return Wheel(Path(line[len(marker) :]).absolute())
    # if for some reason the output does not match fallback to latest version with that spec
    return find_compatible_in_house(distribution, version_spec, for_py_version, to_folder)
def default_config_dir():
    from virtualenv.util.path import Path

    global _CFG_DIR
    if _CFG_DIR is None:
        _CFG_DIR = Path(user_config_dir(appname="virtualenv",
                                        appauthor="pypa"))
    return _CFG_DIR
Beispiel #8
0
    def validate_dest(cls, raw_value):
        """No path separator in the path, valid chars and must be write-able"""

        def non_write_able(dest, value):
            common = Path(*os.path.commonprefix([value.parts, dest.parts]))
            raise ArgumentTypeError(
                "the destination {} is not write-able at {}".format(dest.relative_to(common), common)
            )

        # the file system must be able to encode
        # note in newer CPython this is always utf-8 https://www.python.org/dev/peps/pep-0529/
        encoding = sys.getfilesystemencoding()
        refused = OrderedDict()
        kwargs = {"errors": "ignore"} if encoding != "mbcs" else {}
        for char in six.ensure_text(raw_value):
            try:
                trip = char.encode(encoding, **kwargs).decode(encoding)
                if trip == char:
                    continue
                raise ValueError(trip)
            except ValueError:
                refused[char] = None
        if refused:
            raise ArgumentTypeError(
                "the file system codec ({}) cannot handle characters {!r} within {!r}".format(
                    encoding, "".join(refused.keys()), raw_value
                )
            )
        for char in (i for i in (os.pathsep, os.altsep) if i is not None):
            if char in raw_value:
                raise ArgumentTypeError(
                    "destination {!r} must not contain the path separator ({}) as this would break "
                    "the activation scripts".format(raw_value, char)
                )

        value = Path(raw_value)
        if value.exists() and value.is_file():
            raise ArgumentTypeError("the destination {} already exists and is a file".format(value))
        if (3, 3) <= sys.version_info <= (3, 6):
            # pre 3.6 resolve is always strict, aka must exists, sidestep by using os.path operation
            dest = Path(os.path.realpath(raw_value))
        else:
            dest = value.resolve()
        value = dest
        while dest:
            if dest.exists():
                if os.access(six.ensure_text(str(dest)), os.W_OK):
                    break
                else:
                    non_write_able(dest, value)
            base, _ = dest.parent, dest.name
            if base == dest:
                non_write_able(dest, value)  # pragma: no cover
            dest = base
        return str(value)
Beispiel #9
0
 def _executables(cls, 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
Beispiel #10
0
 def _executables(cls, interpreter):
     host_exe = Path(interpreter.system_executable)
     major, minor = interpreter.version_info.major, interpreter.version_info.minor
     targets = OrderedDict((i, None) for i in [
         "python", "python{}".format(major), "python{}.{}".format(
             major, minor), host_exe.name
     ])
     must = RefMust.COPY if interpreter.version_info.major == 2 else RefMust.NA
     yield host_exe, list(targets.keys()), must, RefWhen.ANY
Beispiel #11
0
    def sources(cls, interpreter):
        for src in super(CPython2macOsFramework, cls).sources(interpreter):
            yield src
        # landmark for exec_prefix
        exec_marker_file, to_path, _ = cls.from_stdlib(
            cls.mappings(interpreter), "lib-dynload")
        yield PathRefToDest(exec_marker_file, dest=to_path)

        # add a copy of the host python image
        exe = Path(interpreter.prefix) / "Python"
        yield PathRefToDest(exe,
                            dest=lambda self, _: self.dest / "Python",
                            must=RefMust.COPY)

        # add a symlink to the Resources dir
        resources = Path(interpreter.prefix) / "Resources"
        yield PathRefToDest(resources,
                            dest=lambda self, _: self.dest / "Resources")
def test_get_release_fails(mocker, caplog):
    exc = RuntimeError("oh no")
    url_o = mocker.patch("virtualenv.seed.wheels.periodic_update.urlopen", side_effect=exc)

    result = release_date_for_wheel_path(Path("pip-20.1.whl"))

    assert result is None
    assert url_o.call_count == 1
    assert repr(exc) in caplog.text
 def __init__(self):
     config_file = os.environ.get(self.VIRTUALENV_CONFIG_FILE_ENV_VAR, None)
     self.is_env_var = config_file is not None
     self.config_file = Path(
         config_file) if config_file is not None else DEFAULT_CONFIG_FILE
     self._cache = {}
     self.has_config_file = self.config_file.exists()
     if self.has_config_file:
         self.config_file = self.config_file.resolve()
         self.config_parser = ConfigParser.ConfigParser()
         try:
             self._load()
             self.has_virtualenv_section = self.config_parser.has_section(
                 self.section)
         except Exception as exception:
             logging.error("failed to read config file %s because %r",
                           config_file, exception)
             self.has_config_file = None
Beispiel #14
0
def test_py_info_cached_symlink(mocker, tmp_path, session_app_data):
    spy = mocker.spy(cached_py_info, "_run_subprocess")
    first_result = PythonInfo.from_exe(sys.executable, session_app_data)
    assert first_result is not None
    count = spy.call_count
    # at least two, one for the venv, one more for the host
    exp_count = 1 if first_result.executable == sys.executable else 2
    assert count >= exp_count  # at least two, one for the venv, one more for the host

    new_exe = tmp_path / "a"
    new_exe.symlink_to(sys.executable)
    pyvenv = Path(sys.executable).parents[1] / "pyvenv.cfg"
    if pyvenv.exists():
        (tmp_path / pyvenv.name).write_text(pyvenv.read_text())
    new_exe_str = str(new_exe)
    second_result = PythonInfo.from_exe(new_exe_str, session_app_data)
    assert second_result.executable == new_exe_str
    assert spy.call_count == count + 1  # no longer needed the host invocation, but the new symlink is must
Beispiel #15
0
    def sources(cls, interpreter):
        for src in super(CPython3macOsFramework, cls).sources(interpreter):
            yield src

        # add a symlink to the host python image
        exe = Path(interpreter.prefix) / "Python3"
        yield PathRefToDest(exe,
                            dest=lambda self, _: self.dest / ".Python",
                            must=RefMust.SYMLINK)
Beispiel #16
0
def fixture_file(fixture_name):
    file_mask = "*{}.json".format(fixture_name)
    files = Path(__file__).parent.parent.rglob(file_mask)
    try:
        return next(files)
    except StopIteration:
        # Fixture file was not found in the testing root and its subdirs.
        error = NameError if PY2 else FileNotFoundError
        raise error(file_mask)
Beispiel #17
0
 def _create_console_entry_point(self, name, value, to_folder,
                                 version_info):
     result = []
     maker = ScriptMakerCustom(to_folder, version_info, self._creator.exe,
                               name)
     specification = "{} = {}".format(name, value)
     new_files = maker.make(specification)
     result.extend(Path(i) for i in new_files)
     return result
Beispiel #18
0
 def _cache_files(self):
     version = self._creator.interpreter.version_info
     py_c_ext = ".{}-{}{}.pyc".format(self._creator.interpreter.implementation.lower(), version.major, version.minor)
     for root, dirs, files in os.walk(six.ensure_text(str(self._image_dir)), topdown=True):
         root_path = Path(root)
         for name in files:
             if name.endswith(".py"):
                 yield root_path / "{}{}".format(name[:-3], py_c_ext)
         for name in dirs:
             yield root_path / name / "__pycache__"
 def _install(name, wheel):
     logging.debug("install %s from wheel %s via %s", name, wheel,
                   installer_class.__name__)
     key = Path(installer_class.__name__) / wheel.path.stem
     wheel_img = self.app_data.wheel_image(
         creator.interpreter.version_release_str, key)
     installer = installer_class(wheel.path, creator, wheel_img)
     if not installer.has_image():
         installer.build_image()
     installer.install(creator.interpreter.version_info)
def old_virtualenv(tmp_path_factory, session_app_data):
    if CURRENT.is_old_virtualenv:
        return CURRENT.executable
    else:
        env_for_old_virtualenv = tmp_path_factory.mktemp(
            "env-for-old-virtualenv")
        result = cli_run([
            "--no-download", "--activators", "",
            str(env_for_old_virtualenv), "--no-periodic-update"
        ])
        # noinspection PyBroadException
        try:
            process = Popen(
                [
                    str(result.creator.script("pip")),
                    "install",
                    "--no-index",
                    "--disable-pip-version-check",
                    str(
                        Path(__file__).resolve().parent /
                        "virtualenv-16.7.9-py2.py3-none-any.whl"),
                    "-v",
                ],
                stdout=subprocess.PIPE,
                stderr=subprocess.PIPE,
            )
            _, __ = process.communicate()
            assert not process.returncode
        except Exception:
            return RuntimeError("failed to install old virtualenv")
        # noinspection PyBroadException
        try:
            old_virtualenv_at = tmp_path_factory.mktemp("old-virtualenv")
            cmd = [
                str(result.creator.script("virtualenv")),
                str(old_virtualenv_at),
                "--no-pip",
                "--no-setuptools",
                "--no-wheel",
            ]
            process = Popen(cmd,
                            stdout=subprocess.PIPE,
                            stderr=subprocess.PIPE)
            _, __ = process.communicate()
            assert not process.returncode
            if result.creator.interpreter.implementation == "PyPy" and IS_WIN:
                # old virtualenv creates pypy paths wrong on windows, so have to hardcode it
                return str(old_virtualenv_at / "bin" / "pypy.exe")
            exe_path = CURRENT.discover_exe(
                session_app_data,
                prefix=str(old_virtualenv_at)).original_executable
            return exe_path
        except Exception as exception:
            return RuntimeError(
                "failed to create old virtualenv {}".format(exception))
Beispiel #21
0
    def sources(cls, interpreter):
        for src in super(CPython2macOsFramework, 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)
        yield ref
Beispiel #22
0
def test_debian_pypy37_virtualenvs(mocker):
    # Debian's pypy3 layout, installed to /usr, before 3.8 allowed a /usr prefix
    inject_fake_path(mocker, ["/usr/bin/pypy3"])
    mocker.patch.object(
        PyPy3Posix,
        "_shared_libs",
        return_value=[Path("/usr/lib/pypy3/bin/libpypy3-c.so")])
    sources = list(
        PyPy3Posix.sources(interpreter=_load_pypi_info("deb_pypy37")))
    assert_contains_exe(sources, "/usr/bin/pypy3")
    assert_contains_ref(sources, "/usr/lib/pypy3/bin/libpypy3-c.so")
    assert len(sources) == 2
Beispiel #23
0
 def _install(name, wheel):
     try:
         logging.debug("install %s from wheel %s via %s", name, wheel, installer_class.__name__)
         key = Path(installer_class.__name__) / wheel.path.stem
         wheel_img = self.app_data.wheel_image(creator.interpreter.version_release_str, key)
         installer = installer_class(wheel.path, creator, wheel_img)
         with _CountedFileLock(ensure_text(str(wheel_img.parent / "{}.lock".format(wheel_img.name)))):
             if not installer.has_image():
                 installer.build_image()
         installer.install(creator.interpreter.version_info)
     except Exception:  # noqa
         exceptions[name] = sys.exc_info()
Beispiel #24
0
def test_download_manual_ignores_pre_release(tmp_path, mocker, freezer):
    freezer.move_to(_UP_NOW)
    wheel = get_embed_wheel("pip", "3.9")
    app_data_outer = AppDataDiskFolder(str(tmp_path / "app"))
    pip_version_remote = [wheel_path(wheel, (0, 0, 1))]
    pip_version_pre = NewVersion(
        Path(wheel_path(wheel, (0, 1, 0), "b1")).name, _UP_NOW, None,
        "downloaded")

    download_wheel = mock_download(mocker, pip_version_remote)
    url_o = mocker.patch("virtualenv.seed.wheels.periodic_update.urlopen",
                         side_effect=URLError("unavailable"))

    last_update = _UP_NOW - timedelta(days=14)
    u_log = UpdateLog(started=last_update,
                      completed=last_update,
                      versions=[pip_version_pre],
                      periodic=True)
    read_dict = mocker.patch(
        "virtualenv.app_data.via_disk_folder.JSONStoreDisk.read",
        return_value=u_log.to_dict())
    write = mocker.patch(
        "virtualenv.app_data.via_disk_folder.JSONStoreDisk.write")

    do_update("pip", "3.9", str(wheel.path), str(app_data_outer), [], False)

    assert download_wheel.call_count == 1
    assert url_o.call_count == 2
    assert read_dict.call_count == 1
    assert write.call_count == 1
    wrote_json = write.call_args[0][0]
    assert wrote_json["versions"] == [
        {
            "filename": Path(pip_version_remote[0]).name,
            "release_date": None,
            "found_date": dump_datetime(_UP_NOW),
            "source": "manual",
        },
        pip_version_pre.to_dict(),
    ]
Beispiel #25
0
    def patch_distutils_via_pth(self):
        """Patch the distutils package to not be derailed by its configuration files"""
        patch_file = Path(__file__).parent / "_distutils_patch_virtualenv.py"
        with ensure_file_on_disk(patch_file, self.app_data) as resolved_path:
            text = resolved_path.read_text()
        text = text.replace('"__SCRIPT_DIR__"', repr(os.path.relpath(str(self.script_dir), str(self.purelib))))
        patch_path = self.purelib / "_distutils_patch_virtualenv.py"
        logging.debug("add distutils patch file %s", patch_path)
        patch_path.write_text(text)

        pth = self.purelib / "_distutils_patch_virtualenv.pth"
        logging.debug("add distutils patch file %s", pth)
        pth.write_text("import _distutils_patch_virtualenv")
def _get_from_cache(cls, app_data, exe, ignore_cache=True):
    # note here we cannot resolve symlinks, as the symlink may trigger different prefix information if there's a
    # pyenv.cfg somewhere alongside on python3.4+
    exe_path = Path(exe)
    if not ignore_cache and exe_path in _CACHE:  # check in the in-memory cache
        result = _CACHE[exe_path]
    else:  # otherwise go through the app data cache
        py_info = _get_via_file_cache(cls, app_data, exe_path, exe)
        result = _CACHE[exe_path] = py_info
    # independent if it was from the file or in-memory cache fix the original executable location
    if isinstance(result, PythonInfo):
        result.executable = exe
    return result
Beispiel #27
0
    def _create_console_entry_point(self, name, value, to_folder):
        result = []
        from distlib.scripts import ScriptMaker

        maker = ScriptMaker(None, str(to_folder))
        maker.clobber = True  # overwrite
        maker.variants = {"", "X", "X.Y"}  # create all variants
        maker.set_mode = True  # ensure they are executable
        maker.executable = str(self._creator.exe)
        specification = "{} = {}".format(name, value)
        new_files = maker.make(specification)
        result.extend(Path(i) for i in new_files)
        return result
Beispiel #28
0
 def _create_console_entry_point(self, name, value, to_folder, version_info):
     result = []
     maker = ScriptMaker(None, str(to_folder))
     maker.clobber = True  # overwrite
     maker.variants = {""}  # set within patch_distlib_correct_variants
     maker.set_mode = True  # ensure they are executable
     # calling private until https://bitbucket.org/pypa/distlib/issues/135/expose-_enquote_executable-as-public
     maker.executable = _enquote_executable(str(self._creator.exe))
     specification = "{} = {}".format(name, value)
     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
Beispiel #29
0
 def _generate_new_files(self):
     new_files = set()
     installer = self._dist_info / "INSTALLER"
     installer.write_text("pip\n")
     new_files.add(installer)
     # inject a no-op root element, as workaround for bug in https://github.com/pypa/pip/issues/7226
     marker = self._image_dir / "{}.virtualenv".format(self._dist_info.stem)
     marker.write_text("")
     new_files.add(marker)
     folder = mkdtemp()
     try:
         to_folder = Path(folder)
         rel = os.path.relpath(ensure_text(str(self._creator.script_dir)), ensure_text(str(self._creator.purelib)))
         version_info = self._creator.interpreter.version_info
         for name, module in self._console_scripts.items():
             new_files.update(
                 Path(os.path.normpath(ensure_text(str(self._image_dir / rel / i.name))))
                 for i in self._create_console_entry_point(name, module, to_folder, version_info)
             )
     finally:
         safe_delete(folder)
     return new_files
Beispiel #30
0
class FakePath(Path):
    """
    A Path() fake that only knows about files in existing_paths and the
    directories that contain them.
    """

    existing_paths = []

    if hasattr(Path(""), "_flavour"):
        _flavour = Path("")._flavour

    def exists(self):
        return self.as_posix() in self.existing_paths or self.is_dir()

    def glob(self, glob):
        pattern = self.as_posix() + "/" + glob
        for path in fnmatch.filter(self.existing_paths, pattern):
            yield FakePath(path)

    def is_dir(self):
        prefix = self.as_posix() + "/"
        return any(True for path in self.existing_paths
                   if path.startswith(prefix))

    def iterdir(self):
        prefix = self.as_posix() + "/"
        for path in self.existing_paths:
            if path.startswith(prefix) and "/" not in path[len(prefix):]:
                yield FakePath(path)

    def resolve(self):
        return self

    def __div__(self, key):
        return FakePath(super(FakePath, self).__div__(key))

    def __truediv__(self, key):
        return FakePath(super(FakePath, self).__truediv__(key))