Beispiel #1
0
def test_get_prefers_explicitly_activated_virtualenvs_over_env_var(
        tmp_dir, config, mocker):
    os.environ["VIRTUAL_ENV"] = "/environment/prefix"

    venv_name = EnvManager.generate_env_name("simple_project", str(CWD))

    config.add_property("settings.virtualenvs.path", str(tmp_dir))
    (Path(tmp_dir) / "{}-py3.7".format(venv_name)).mkdir()

    envs_file = TomlFile(Path(tmp_dir) / "envs.toml")
    doc = tomlkit.document()
    doc[venv_name] = {"minor": "3.7", "patch": "3.7.0"}
    envs_file.write(doc)

    mocker.patch(
        "poetry.utils._compat.subprocess.check_output",
        side_effect=check_output_wrapper(),
    )
    mocker.patch(
        "poetry.utils._compat.subprocess.Popen.communicate",
        side_effect=[("/prefix", None)],
    )

    env = EnvManager(config).get(CWD)

    assert env.path == Path(tmp_dir) / "{}-py3.7".format(venv_name)
    assert env.base == Path("/prefix")
Beispiel #2
0
def test_remove_also_deactivates(tmp_dir, config, mocker):
    config.add_property("settings.virtualenvs.path", str(tmp_dir))

    venv_name = EnvManager.generate_env_name("simple_project", str(CWD))
    (Path(tmp_dir) / "{}-py3.7".format(venv_name)).mkdir()
    (Path(tmp_dir) / "{}-py3.6".format(venv_name)).mkdir()

    mocker.patch(
        "poetry.utils._compat.subprocess.check_output",
        side_effect=check_output_wrapper(Version.parse("3.6.6")),
    )

    envs_file = TomlFile(Path(tmp_dir) / "envs.toml")
    doc = tomlkit.document()
    doc[venv_name] = {"minor": "3.6", "patch": "3.6.6"}
    envs_file.write(doc)

    manager = EnvManager(config)

    venv = manager.remove("python3.6", CWD)

    assert (Path(tmp_dir) / "{}-py3.6".format(venv_name)) == venv.path
    assert not (Path(tmp_dir) / "{}-py3.6".format(venv_name)).exists()

    envs = envs_file.read()
    assert venv_name not in envs
Beispiel #3
0
def test_activated(app, tmp_dir, config):
    app.poetry._config = config

    config.add_property("settings.virtualenvs.path", str(tmp_dir))

    venv_name = EnvManager.generate_env_name("simple_project",
                                             str(app.poetry.file.parent))
    (Path(tmp_dir) / "{}-py3.7".format(venv_name)).mkdir()
    (Path(tmp_dir) / "{}-py3.6".format(venv_name)).mkdir()

    envs_file = TomlFile(Path(tmp_dir) / "envs.toml")
    doc = tomlkit.document()
    doc[venv_name] = {"minor": "3.7", "patch": "3.7.0"}
    envs_file.write(doc)

    command = app.find("env list")
    tester = CommandTester(command)
    tester.execute()

    expected = """\
{}-py3.6
{}-py3.7 (Activated)
""".format(venv_name, venv_name)

    assert expected == tester.io.fetch_output()
def test_activate_activates_recreates_for_different_patch(
    tmp_dir, manager, poetry, config, mocker
):
    if "VIRTUAL_ENV" in os.environ:
        del os.environ["VIRTUAL_ENV"]

    venv_name = manager.generate_env_name("simple-project", str(poetry.file.parent))
    envs_file = TomlFile(Path(tmp_dir) / "envs.toml")
    doc = tomlkit.document()
    doc[venv_name] = {"minor": "3.7", "patch": "3.7.0"}
    envs_file.write(doc)

    os.mkdir(os.path.join(tmp_dir, "{}-py3.7".format(venv_name)))

    config.merge({"virtualenvs": {"path": str(tmp_dir)}})

    mocker.patch(
        "poetry.utils._compat.subprocess.check_output",
        side_effect=check_output_wrapper(),
    )
    mocker.patch(
        "poetry.utils._compat.subprocess.Popen.communicate",
        side_effect=[
            ("/prefix", None),
            ('{"version_info": [3, 7, 0]}', None),
            ("/prefix", None),
            ("/prefix", None),
            ("/prefix", None),
        ],
    )
    build_venv_m = mocker.patch(
        "poetry.utils.env.EnvManager.build_venv", side_effect=build_venv
    )
    remove_venv_m = mocker.patch(
        "poetry.utils.env.EnvManager.remove_venv", side_effect=remove_venv
    )

    env = manager.activate("python3.7", NullIO())

    build_venv_m.assert_called_with(
        os.path.join(tmp_dir, "{}-py3.7".format(venv_name)), executable="python3.7"
    )
    remove_venv_m.assert_called_with(
        os.path.join(tmp_dir, "{}-py3.7".format(venv_name))
    )

    assert envs_file.exists()
    envs = envs_file.read()
    assert envs[venv_name]["minor"] == "3.7"
    assert envs[venv_name]["patch"] == "3.7.1"

    assert env.path == Path(tmp_dir) / "{}-py3.7".format(venv_name)
    assert env.base == Path("/prefix")
    assert (Path(tmp_dir) / "{}-py3.7".format(venv_name)).exists()
Beispiel #5
0
def test_activate_does_not_recreate_when_switching_minor(tmp_dir, config, mocker):
    if "VIRTUAL_ENV" in os.environ:
        del os.environ["VIRTUAL_ENV"]

    venv_name = EnvManager.generate_env_name("simple_project", str(CWD))
    envs_file = TomlFile(Path(tmp_dir) / "envs.toml")
    doc = tomlkit.document()
    doc[venv_name] = {"minor": "3.7", "patch": "3.7.0"}
    envs_file.write(doc)

    os.mkdir(os.path.join(tmp_dir, "{}-py3.7".format(venv_name)))
    os.mkdir(os.path.join(tmp_dir, "{}-py3.6".format(venv_name)))

    config.merge({"virtualenvs": {"path": str(tmp_dir)}})

    mocker.patch(
        "poetry.utils._compat.subprocess.check_output",
        side_effect=check_output_wrapper(Version.parse("3.6.6")),
    )
    mocker.patch(
        "poetry.utils._compat.subprocess.Popen.communicate",
        side_effect=[("/prefix", None), ("/prefix", None), ("/prefix", None)],
    )
    build_venv_m = mocker.patch(
        "poetry.utils.env.EnvManager.build_venv", side_effect=build_venv
    )
    remove_venv_m = mocker.patch(
        "poetry.utils.env.EnvManager.remove_venv", side_effect=remove_venv
    )

    env = EnvManager(config).activate("python3.6", CWD, NullIO())

    build_venv_m.assert_not_called()
    remove_venv_m.assert_not_called()

    assert envs_file.exists()
    envs = envs_file.read()
    assert envs[venv_name]["minor"] == "3.6"
    assert envs[venv_name]["patch"] == "3.6.6"

    assert env.path == Path(tmp_dir) / "{}-py3.6".format(venv_name)
    assert env.base == Path("/prefix")
    assert (Path(tmp_dir) / "{}-py3.6".format(venv_name)).exists()
Beispiel #6
0
def test_get_prefers_explicitly_activated_virtualenvs_over_env_var(
    app, tmp_dir, mocker
):
    mocker.stopall()
    os.environ["VIRTUAL_ENV"] = "/environment/prefix"

    venv_name = EnvManager.generate_env_name(
        "simple-project", str(app.poetry.file.parent)
    )
    current_python = sys.version_info[:3]
    python_minor = ".".join(str(v) for v in current_python[:2])
    python_patch = ".".join(str(v) for v in current_python)

    app.poetry.config.merge({"virtualenvs": {"path": str(tmp_dir)}})
    (Path(tmp_dir) / "{}-py{}".format(venv_name, python_minor)).mkdir()

    envs_file = TomlFile(Path(tmp_dir) / "envs.toml")
    doc = tomlkit.document()
    doc[venv_name] = {"minor": python_minor, "patch": python_patch}
    envs_file.write(doc)

    mocker.patch(
        "poetry.utils._compat.subprocess.check_output",
        side_effect=check_output_wrapper(Version(*current_python)),
    )
    mocker.patch(
        "poetry.utils._compat.subprocess.Popen.communicate",
        side_effect=[("/prefix", None), ("/prefix", None), ("/prefix", None)],
    )

    command = app.find("env use")
    tester = CommandTester(command)
    tester.execute(python_minor)

    expected = """\
Using virtualenv: {}
""".format(
        os.path.join(tmp_dir, "{}-py{}".format(venv_name, python_minor))
    )

    assert expected == tester.io.fetch_output()
Beispiel #7
0
    def deactivate(self, io):  # type: (IO) -> None
        venv_path = self._poetry.config.get("virtualenvs.path")
        if venv_path is None:
            venv_path = Path(CACHE_DIR) / "virtualenvs"
        else:
            venv_path = Path(venv_path)

        name = self._poetry.package.name
        name = self.generate_env_name(name, str(self._poetry.file.parent))

        envs_file = TomlFile(venv_path / self.ENVS_FILE)
        if envs_file.exists():
            envs = envs_file.read()
            env = envs.get(name)
            if env is not None:
                io.write_line(
                    "Deactivating virtualenv: <comment>{}</comment>".format(
                        venv_path / (name + "-py{}".format(env["minor"]))))
                del envs[name]

                envs_file.write(envs)
Beispiel #8
0
    def deactivate(self, cwd, io):  # type: (Optional[Path], IO) -> None
        venv_path = self._config.setting("settings.virtualenvs.path")
        if venv_path is None:
            venv_path = Path(CACHE_DIR) / "virtualenvs"
        else:
            venv_path = Path(venv_path)

        name = cwd.name
        name = self.generate_env_name(name, str(cwd))

        envs_file = TomlFile(venv_path / self.ENVS_FILE)
        if envs_file.exists():
            envs = envs_file.read()
            env = envs.get(name)
            if env is not None:
                io.write_line(
                    "Deactivating virtualenv: <comment>{}</comment>".format(
                        venv_path / (name + "-py{}".format(env["minor"]))))
                del envs[name]

                envs_file.write(envs)
Beispiel #9
0
def test_get_prefers_explicitly_activated_virtualenvs_over_env_var(
        tester, current_python, venv_cache, venv_name, venvs_in_cache_config):
    os.environ["VIRTUAL_ENV"] = "/environment/prefix"

    python_minor = ".".join(str(v) for v in current_python[:2])
    python_patch = ".".join(str(v) for v in current_python[:3])
    venv_dir = venv_cache / "{}-py{}".format(venv_name, python_minor)
    venv_dir.mkdir(parents=True, exist_ok=True)

    envs_file = TomlFile(venv_cache / "envs.toml")
    doc = tomlkit.document()
    doc[venv_name] = {"minor": python_minor, "patch": python_patch}
    envs_file.write(doc)

    tester.execute(python_minor)

    expected = """\
Using virtualenv: {}
""".format(venv_dir)

    assert expected == tester.io.fetch_output()
Beispiel #10
0
def test_deactivate_activated(tmp_dir, manager, poetry, config, mocker):
    if "VIRTUAL_ENV" in os.environ:
        del os.environ["VIRTUAL_ENV"]

    venv_name = manager.generate_env_name("simple-project", str(poetry.file.parent))
    version = Version.parse(".".join(str(c) for c in sys.version_info[:3]))
    other_version = Version.parse("3.4") if version.major == 2 else version.next_minor
    (
        Path(tmp_dir) / "{}-py{}.{}".format(venv_name, version.major, version.minor)
    ).mkdir()
    (
        Path(tmp_dir)
        / "{}-py{}.{}".format(venv_name, other_version.major, other_version.minor)
    ).mkdir()

    envs_file = TomlFile(Path(tmp_dir) / "envs.toml")
    doc = tomlkit.document()
    doc[venv_name] = {
        "minor": "{}.{}".format(other_version.major, other_version.minor),
        "patch": other_version.text,
    }
    envs_file.write(doc)

    config.merge({"virtualenvs": {"path": str(tmp_dir)}})

    mocker.patch(
        "poetry.utils._compat.subprocess.check_output",
        side_effect=check_output_wrapper(),
    )

    manager.deactivate(NullIO())
    env = manager.get()

    assert env.path == Path(tmp_dir) / "{}-py{}.{}".format(
        venv_name, version.major, version.minor
    )
    assert Path("/prefix")

    envs = envs_file.read()
    assert len(envs) == 0
Beispiel #11
0
def test_activate_activates_different_virtualenv_with_envs_file(
        tmp_dir, config, mocker):
    if "VIRTUAL_ENV" in os.environ:
        del os.environ["VIRTUAL_ENV"]

    venv_name = EnvManager.generate_env_name("simple_project", str(CWD))
    envs_file = TomlFile(Path(tmp_dir) / "envs.toml")
    doc = tomlkit.document()
    doc[venv_name] = {"minor": "3.7", "patch": "3.7.1"}
    envs_file.write(doc)

    os.mkdir(os.path.join(tmp_dir, "{}-py3.7".format(venv_name)))

    config.add_property("settings.virtualenvs.path", str(tmp_dir))

    mocker.patch(
        "poetry.utils._compat.subprocess.check_output",
        side_effect=check_output_wrapper(Version.parse("3.6.6")),
    )
    mocker.patch(
        "poetry.utils._compat.subprocess.Popen.communicate",
        side_effect=[("/prefix", None), ("/prefix", None), ("/prefix", None)],
    )
    m = mocker.patch("poetry.utils.env.EnvManager.build_venv",
                     side_effect=build_venv)

    env = EnvManager(config).activate("python3.6", CWD, NullIO())

    m.assert_called_with(os.path.join(tmp_dir, "{}-py3.6".format(venv_name)),
                         executable="python3.6")

    assert envs_file.exists()
    envs = envs_file.read()
    assert envs[venv_name]["minor"] == "3.6"
    assert envs[venv_name]["patch"] == "3.6.6"

    assert env.path == Path(tmp_dir) / "{}-py3.6".format(venv_name)
    assert env.base == Path("/prefix")
Beispiel #12
0
    def remove(self, python):  # type: (str) -> Env
        venv_path = self._poetry.config.get("virtualenvs.path")
        if venv_path is None:
            venv_path = Path(CACHE_DIR) / "virtualenvs"
        else:
            venv_path = Path(venv_path)

        cwd = self._poetry.file.parent
        envs_file = TomlFile(venv_path / self.ENVS_FILE)
        base_env_name = self.generate_env_name(self._poetry.package.name,
                                               str(cwd))

        if python.startswith(base_env_name):
            venvs = self.list()
            for venv in venvs:
                if venv.path.name == python:
                    # Exact virtualenv name
                    if not envs_file.exists():
                        self.remove_venv(str(venv.path))

                        return venv

                    venv_minor = ".".join(
                        str(v) for v in venv.version_info[:2])
                    base_env_name = self.generate_env_name(cwd.name, str(cwd))
                    envs = envs_file.read()

                    current_env = envs.get(base_env_name)
                    if not current_env:
                        self.remove_venv(str(venv.path))

                        return venv

                    if current_env["minor"] == venv_minor:
                        del envs[base_env_name]
                        envs_file.write(envs)

                    self.remove_venv(str(venv.path))

                    return venv

            raise ValueError(
                '<warning>Environment "{}" does not exist.</warning>'.format(
                    python))

        try:
            python_version = Version.parse(python)
            python = "python{}".format(python_version.major)
            if python_version.precision > 1:
                python += ".{}".format(python_version.minor)
        except ValueError:
            # Executable in PATH or full executable path
            pass

        try:
            python_version = decode(
                subprocess.check_output(
                    " ".join([
                        python,
                        "-c",
                        "\"import sys; print('.'.join([str(s) for s in sys.version_info[:3]]))\"",
                    ]),
                    shell=True,
                ))
        except CalledProcessError as e:
            raise EnvCommandError(e)

        python_version = Version.parse(python_version.strip())
        minor = "{}.{}".format(python_version.major, python_version.minor)

        name = "{}-py{}".format(base_env_name, minor)
        venv = venv_path / name

        if not venv.exists():
            raise ValueError(
                '<warning>Environment "{}" does not exist.</warning>'.format(
                    name))

        if envs_file.exists():
            envs = envs_file.read()
            current_env = envs.get(base_env_name)
            if current_env is not None:
                current_minor = current_env["minor"]

                if current_minor == minor:
                    del envs[base_env_name]
                    envs_file.write(envs)

        self.remove_venv(str(venv))

        return VirtualEnv(venv)
Beispiel #13
0
    def activate(self, python, io):  # type: (str, IO) -> Env
        venv_path = self._poetry.config.get("virtualenvs.path")
        if venv_path is None:
            venv_path = Path(CACHE_DIR) / "virtualenvs"
        else:
            venv_path = Path(venv_path)

        cwd = self._poetry.file.parent

        envs_file = TomlFile(venv_path / self.ENVS_FILE)

        try:
            python_version = Version.parse(python)
            python = "python{}".format(python_version.major)
            if python_version.precision > 1:
                python += ".{}".format(python_version.minor)
        except ValueError:
            # Executable in PATH or full executable path
            pass

        try:
            python_version = decode(
                subprocess.check_output(
                    " ".join([
                        python,
                        "-c",
                        "\"import sys; print('.'.join([str(s) for s in sys.version_info[:3]]))\"",
                    ]),
                    shell=True,
                ))
        except CalledProcessError as e:
            raise EnvCommandError(e)

        python_version = Version.parse(python_version.strip())
        minor = "{}.{}".format(python_version.major, python_version.minor)
        patch = python_version.text

        create = False
        envs = tomlkit.document()
        base_env_name = self.generate_env_name(self._poetry.package.name,
                                               str(cwd))
        if envs_file.exists():
            envs = envs_file.read()
            current_env = envs.get(base_env_name)
            if current_env is not None:
                current_minor = current_env["minor"]
                current_patch = current_env["patch"]

                if current_minor == minor and current_patch != patch:
                    # We need to recreate
                    create = True

        name = "{}-py{}".format(base_env_name, minor)
        venv = venv_path / name

        # Create if needed
        if not venv.exists() or venv.exists() and create:
            in_venv = os.environ.get("VIRTUAL_ENV") is not None
            if in_venv or not venv.exists():
                create = True

            if venv.exists():
                # We need to check if the patch version is correct
                _venv = VirtualEnv(venv)
                current_patch = ".".join(
                    str(v) for v in _venv.version_info[:3])

                if patch != current_patch:
                    create = True

            self.create_venv(io, executable=python, force=create)

        # Activate
        envs[base_env_name] = {"minor": minor, "patch": patch}
        envs_file.write(envs)

        return self.get(reload=True)
Beispiel #14
0
class Locker:

    _relevant_keys = [
        'name',
        'version',
        'python-versions',
        'platform',
        'dependencies',
        'dev-dependencies',
        'source',
    ]

    def __init__(self, lock: Path, local_config: dict):
        self._lock = TomlFile(lock)
        self._local_config = local_config
        self._lock_data = None
        self._content_hash = self._get_content_hash()

    @property
    def lock(self) -> TomlFile:
        return self._lock

    @property
    def lock_data(self):
        if self._lock_data is None:
            self._lock_data = self._get_lock_data()

        return self._lock_data

    def is_locked(self) -> bool:
        """
        Checks whether the locker has been locked (lockfile found).
        """
        if not self._lock.exists():
            return False

        return 'package' in self.lock_data

    def is_fresh(self) -> bool:
        """
        Checks whether the lock file is still up to date with the current hash.
        """
        lock = self._lock.read(True)
        metadata = lock.get('metadata', {})

        if 'content-hash' in metadata:
            return self._content_hash == lock['metadata']['content-hash']

        return False

    def locked_repository(self, with_dev_reqs: bool = False) -> Repository:
        """
        Searches and returns a repository of locked packages.
        """
        if not self.is_locked():
            return Repository()

        lock_data = self.lock_data
        packages = Repository()

        if with_dev_reqs:
            locked_packages = lock_data['package']
        else:
            locked_packages = [
                p for p in lock_data['package'] if p['category'] == 'main'
            ]

        if not locked_packages:
            return packages

        for info in locked_packages:
            package = poetry.packages.Package(
                info['name'],
                info['version'],
                info['version']
            )
            package.description = info.get('description', '')
            package.category = info['category']
            package.optional = info['optional']
            package.hashes = lock_data['metadata']['hashes'][info['name']]
            package.python_versions = info['python-versions']

            for dep_name, constraint in info.get('dependencies', {}).items():
                package.add_dependency(dep_name, constraint)

            if 'source' in info:
                package.source_type = info['source']['type']
                package.source_url = info['source']['url']
                package.source_reference = info['source']['reference']

            packages.add_package(package)

        return packages

    def set_lock_data(self,
                      root, packages) -> bool:
        hashes = {}
        packages = self._lock_packages(packages)
        # Retrieving hashes
        for package in packages:
            hashes[package['name']] = package['hashes']
            del package['hashes']

        lock = {
            'package': packages,
            'metadata': {
                'python-versions': root.python_versions,
                'platform': root.platform,
                'content-hash': self._content_hash,
                'hashes': hashes,
            }
        }

        if root.extras:
            lock['extras'] = {
                extra: [dep.pretty_name for dep in deps]
                for extra, deps in root.extras.items()
            }

        if not self.is_locked() or lock != self.lock_data:
            self._write_lock_data(lock)

            return True

        return False

    def _write_lock_data(self, data):
        self._lock.write(data)
        self._lock_data = None

    def _get_content_hash(self) -> str:
        """
        Returns the sha256 hash of the sorted content of the composer file.
        """
        content = self._local_config

        relevant_content = {}
        for key in self._relevant_keys:
            relevant_content[key] = content.get(key)

        content_hash = sha256(
            json.dumps(relevant_content, sort_keys=True).encode()
        ).hexdigest()

        return content_hash

    def _get_lock_data(self) -> dict:
        if not self._lock.exists():
            raise RuntimeError(
                'No lockfile found. Unable to read locked packages'
            )

        return self._lock.read(True)

    def _lock_packages(self,
                       packages: List['poetry.packages.Package']) -> list:
        locked = []

        for package in sorted(packages, key=lambda x: x.name):
            spec = self._dump_package(package)

            locked.append(spec)

        return locked

    def _dump_package(self, package: 'poetry.packages.Package') -> dict:
        dependencies = {}
        for dependency in package.requires:
            if dependency.is_optional():
                continue

            dependencies[dependency.pretty_name] = dependency.pretty_constraint

        data = {
            'name': package.pretty_name,
            'version': package.pretty_version,
            'description': package.description,
            'category': package.category,
            'optional': package.optional,
            'python-versions': package.python_versions,
            'platform': package.platform,
            'hashes': package.hashes,
            'dependencies': dependencies
        }

        if package.source_type:
            data['source'] = {
                'type': package.source_type,
                'url': package.source_url,
                'reference': package.source_reference
            }

        if package.requirements:
            data['requirements'] = package.requirements

        return data
Beispiel #15
0
class Locker:

    _relevant_keys = ["dependencies", "dev-dependencies", "source"]

    def __init__(self, lock, local_config):  # type: (Path, dict) -> None
        self._lock = TomlFile(lock)
        self._local_config = local_config
        self._lock_data = None
        self._content_hash = self._get_content_hash()

    @property
    def lock(self):  # type: () -> TomlFile
        return self._lock

    @property
    def lock_data(self):
        if self._lock_data is None:
            self._lock_data = self._get_lock_data()

        return self._lock_data

    def is_locked(self):  # type: () -> bool
        """
        Checks whether the locker has been locked (lockfile found).
        """
        if not self._lock.exists():
            return False

        return "package" in self.lock_data

    def is_fresh(self):  # type: () -> bool
        """
        Checks whether the lock file is still up to date with the current hash.
        """
        lock = self._lock.read(True)
        metadata = lock.get("metadata", {})

        if "content-hash" in metadata:
            return self._content_hash == lock["metadata"]["content-hash"]

        return False

    def locked_repository(self,
                          with_dev_reqs=False
                          ):  # type: (bool) -> poetry.repositories.Repository
        """
        Searches and returns a repository of locked packages.
        """
        if not self.is_locked():
            return poetry.repositories.Repository()

        lock_data = self.lock_data
        packages = poetry.repositories.Repository()

        if with_dev_reqs:
            locked_packages = lock_data["package"]
        else:
            locked_packages = [
                p for p in lock_data["package"] if p["category"] == "main"
            ]

        if not locked_packages:
            return packages

        for info in locked_packages:
            package = poetry.packages.Package(info["name"], info["version"],
                                              info["version"])
            package.description = info.get("description", "")
            package.category = info["category"]
            package.optional = info["optional"]
            package.hashes = lock_data["metadata"]["hashes"][info["name"]]
            package.python_versions = info["python-versions"]

            for dep_name, constraint in info.get("dependencies", {}).items():
                package.add_dependency(dep_name, constraint)

            if "requirements" in info:
                package.requirements = info["requirements"]

            if "source" in info:
                package.source_type = info["source"]["type"]
                package.source_url = info["source"]["url"]
                package.source_reference = info["source"]["reference"]

            packages.add_package(package)

        return packages

    def set_lock_data(self, root, packages):  # type: () -> bool
        hashes = {}
        packages = self._lock_packages(packages)
        # Retrieving hashes
        for package in packages:
            hashes[package["name"]] = package["hashes"]
            del package["hashes"]

        lock = {
            "package": packages,
            "metadata": {
                "python-versions": root.python_versions,
                "platform": root.platform,
                "content-hash": self._content_hash,
                "hashes": hashes,
            },
        }

        if root.extras:
            lock["extras"] = {
                extra: [dep.pretty_name for dep in deps]
                for extra, deps in root.extras.items()
            }

        if not self.is_locked() or lock != self.lock_data:
            self._write_lock_data(lock)

            return True

        return False

    def _write_lock_data(self, data):
        self._lock.write(data)
        self._lock_data = None

    def _get_content_hash(self):  # type: () -> str
        """
        Returns the sha256 hash of the sorted content of the composer file.
        """
        content = self._local_config

        relevant_content = {}
        for key in self._relevant_keys:
            relevant_content[key] = content.get(key)

        content_hash = sha256(
            json.dumps(relevant_content, sort_keys=True).encode()).hexdigest()

        return content_hash

    def _get_lock_data(self):  # type: () -> dict
        if not self._lock.exists():
            raise RuntimeError(
                "No lockfile found. Unable to read locked packages")

        return self._lock.read(True)

    def _lock_packages(
            self, packages):  # type: (List['poetry.packages.Package']) -> list
        locked = []

        for package in sorted(packages, key=lambda x: x.name):
            spec = self._dump_package(package)

            locked.append(spec)

        return locked

    def _dump_package(self,
                      package):  # type: (poetry.packages.Package) -> dict
        dependencies = {}
        for dependency in package.requires:
            if dependency.is_optional() and not dependency.is_activated():
                continue

            dependencies[dependency.pretty_name] = str(
                dependency.pretty_constraint)

        data = {
            "name": package.pretty_name,
            "version": package.pretty_version,
            "description": package.description,
            "category": package.category,
            "optional": package.optional,
            "python-versions": package.python_versions,
            "platform": package.platform,
            "hashes": package.hashes,
            "dependencies": dependencies,
        }

        if package.source_type:
            data["source"] = {
                "type": package.source_type,
                "url": package.source_url,
                "reference": package.source_reference,
            }

        if package.requirements:
            data["requirements"] = package.requirements

        return data
Beispiel #16
0
def venv_activate_37(venv_cache, venv_name):
    envs_file = TomlFile(venv_cache / "envs.toml")
    doc = tomlkit.document()
    doc[venv_name] = {"minor": "3.7", "patch": "3.7.0"}
    envs_file.write(doc)