Esempio n. 1
0
    def _install_directory(self, operation: Union[Install, Update]) -> int:
        from poetry.factory import Factory

        package = operation.package
        operation_message = self.get_operation_message(operation)

        message = (
            "  <fg=blue;options=bold>•</> {message}: <info>Building...</info>".
            format(message=operation_message, ))
        self._write(operation, message)

        if package.root_dir:
            req = package.root_dir / package.source_url
        else:
            req = Path(package.source_url).resolve(strict=False)

        pyproject = PyProjectTOML(os.path.join(req, "pyproject.toml"))

        if pyproject.is_poetry_project():
            # Even if there is a build system specified
            # some versions of pip (< 19.0.0) don't understand it
            # so we need to check the version of pip to know
            # if we can rely on the build system
            legacy_pip = (self._env.pip_version <
                          self._env.pip_version.__class__.from_parts(19, 0, 0))
            package_poetry = Factory().create_poetry(
                pyproject.file.path.parent)

            if package.develop and not package_poetry.package.build_script:
                from poetry.masonry.builders.editable import EditableBuilder

                # This is a Poetry package in editable mode
                # we can use the EditableBuilder without going through pip
                # to install it, unless it has a build script.
                builder = EditableBuilder(package_poetry, self._env, NullIO())
                builder.build()

                return 0
            elif legacy_pip or package_poetry.package.build_script:
                from poetry.core.masonry.builders.sdist import SdistBuilder

                # We need to rely on creating a temporary setup.py
                # file since the version of pip does not support
                # build-systems
                # We also need it for non-PEP-517 packages
                builder = SdistBuilder(package_poetry)

                with builder.setup_py():
                    if package.develop:
                        return pip_editable_install(req, self._env)
                    return pip_install(req, self._env, upgrade=True)

        if package.develop:
            return pip_editable_install(req, self._env)

        return pip_install(req, self._env, upgrade=True)
Esempio n. 2
0
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(
        "subprocess.check_output",
        side_effect=check_output_wrapper(),
    )
    mocker.patch(
        "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=EnvManager.remove_venv)

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

    build_venv_m.assert_called_with(
        Path(tmp_dir) / "{}-py3.7".format(venv_name),
        executable="python3.7",
        flags={
            "always-copy": False,
            "system-site-packages": False
        },
    )
    remove_venv_m.assert_called_with(
        Path(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()
Esempio n. 3
0
    def create_poetry(
        self,
        cwd: Path | None = None,
        io: IO | None = None,
        disable_plugins: bool = False,
    ) -> Poetry:
        if io is None:
            io = NullIO()

        base_poetry = super().create_poetry(cwd)

        locker = Locker(base_poetry.file.parent / "poetry.lock",
                        base_poetry.local_config)

        # Loading global configuration
        config = self.create_config(io)

        # Loading local configuration
        local_config_file = TOMLFile(base_poetry.file.parent / "poetry.toml")
        if local_config_file.exists():
            if io.is_debug():
                io.write_line(
                    f"Loading configuration file {local_config_file.path}")

            config.merge(local_config_file.read())

        # Load local sources
        repositories = {}
        existing_repositories = config.get("repositories", {})
        for source in base_poetry.pyproject.poetry_config.get("source", []):
            name = source.get("name")
            url = source.get("url")
            if name and url and name not in existing_repositories:
                repositories[name] = {"url": url}

        config.merge({"repositories": repositories})

        poetry = Poetry(
            base_poetry.file.path,
            base_poetry.local_config,
            base_poetry.package,
            locker,
            config,
        )

        # Configuring sources
        self.configure_sources(poetry, poetry.local_config.get("source", []),
                               config, io)

        plugin_manager = PluginManager("plugin",
                                       disable_plugins=disable_plugins)
        plugin_manager.load_plugins()
        poetry.set_plugin_manager(plugin_manager)
        plugin_manager.activate(poetry, io)

        return poetry
Esempio n. 4
0
def test_publish_raises_error_for_undefined_repository(fixture_dir, mocker, config):
    poetry = Factory().create_poetry(fixture_dir("sample_project"))
    poetry._config = config
    poetry.config.merge(
        {"http-basic": {"my-repo": {"username": "******", "password": "******"}}}
    )
    publisher = Publisher(poetry, NullIO())

    with pytest.raises(RuntimeError):
        publisher.publish("my-repo", None, None)
Esempio n. 5
0
def test_authenticator_uses_url_provided_credentials(
        mock_config: Config, mock_remote: None,
        http: type[httpretty.httpretty]):
    authenticator = Authenticator(mock_config, NullIO())
    authenticator.request(
        "get", "https://*****:*****@foo.bar/files/foo-0.1.0.tar.gz")

    request = http.last_request()

    assert request.headers["Authorization"] == "Basic Zm9vMDAxOmJhcjAwMg=="
Esempio n. 6
0
    def install_directory(self, package: "Package") -> Union[str, int]:
        from cleo.io.null_io import NullIO

        from poetry.factory import Factory

        req: Path

        if package.root_dir:
            req = (package.root_dir / package.source_url).as_posix()
        else:
            req = Path(package.source_url).resolve(strict=False)

        pyproject = PyProjectTOML(os.path.join(req, "pyproject.toml"))

        if pyproject.is_poetry_project():
            # Even if there is a build system specified
            # some versions of pip (< 19.0.0) don't understand it
            # so we need to check the version of pip to know
            # if we can rely on the build system
            legacy_pip = self._env.pip_version < self._env.pip_version.__class__(
                19, 0, 0
            )
            package_poetry = Factory().create_poetry(pyproject.file.path.parent)

            if package.develop and not package_poetry.package.build_script:
                from poetry.masonry.builders.editable import EditableBuilder

                # This is a Poetry package in editable mode
                # we can use the EditableBuilder without going through pip
                # to install it, unless it has a build script.
                builder = EditableBuilder(package_poetry, self._env, NullIO())
                builder.build()

                return 0
            elif legacy_pip or package_poetry.package.build_script:
                from poetry.core.masonry.builders.sdist import SdistBuilder

                # We need to rely on creating a temporary setup.py
                # file since the version of pip does not support
                # build-systems
                # We also need it for non-PEP-517 packages
                builder = SdistBuilder(package_poetry)

                with builder.setup_py():
                    if package.develop:
                        return pip_editable_install(
                            directory=req, environment=self._env
                        )
                    return pip_install(
                        path=req, environment=self._env, deps=False, upgrade=True
                    )

        if package.develop:
            return pip_editable_install(directory=req, environment=self._env)
        return pip_install(path=req, environment=self._env, deps=False, upgrade=True)
Esempio n. 7
0
def test_authenticator_uses_env_provided_credentials(
        config, environ, mock_remote, http,
        environment_repository_credentials):
    config.merge({"repositories": {"foo": {"url": "https://foo.bar/simple/"}}})

    authenticator = Authenticator(config, NullIO())
    authenticator.request("get", "https://foo.bar/files/foo-0.1.0.tar.gz")

    request = http.last_request()

    assert "Basic YmFyOmJheg==" == request.headers["Authorization"]
Esempio n. 8
0
    def call_silent(self, name, args=None):  # type: (str, Optional[str]) -> int
        """
        Call another command silently.
        """
        if args is None:
            args = ""

        args = StringInput(args)
        command = self.application.get(name)

        return self.application._run_command(command, NullIO(input))
Esempio n. 9
0
def test_builder_falls_back_on_setup_and_pip_for_packages_with_build_scripts(
        mocker, extended_poetry, tmp_dir):
    pip_editable_install = mocker.patch(
        "poetry.masonry.builders.editable.pip_editable_install")
    env = MockEnv(path=Path(tmp_dir) / "foo")
    builder = EditableBuilder(extended_poetry, env, NullIO())

    builder.build()
    pip_editable_install.assert_called_once_with(
        extended_poetry.pyproject.file.path.parent, env)
    assert [] == env.executed
Esempio n. 10
0
def test_builder_should_execute_build_scripts(extended_without_setup_poetry,
                                              tmp_dir):
    env = MockEnv(path=Path(tmp_dir) / "foo")
    builder = EditableBuilder(extended_without_setup_poetry, env, NullIO())

    builder.build()

    assert [[
        "python",
        str(extended_without_setup_poetry.file.parent / "build.py")
    ]] == env.executed
Esempio n. 11
0
def test_activate_activates_different_virtualenv_with_envs_file(
    tmp_dir: str,
    manager: EnvManager,
    poetry: Poetry,
    config: Config,
    mocker: MockerFixture,
):
    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.1"}
    envs_file.write(doc)

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

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

    mocker.patch(
        "subprocess.check_output",
        side_effect=check_output_wrapper(Version.parse("3.6.6")),
    )
    mocker.patch(
        "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 = manager.activate("python3.6", NullIO())

    m.assert_called_with(
        Path(tmp_dir) / f"{venv_name}-py3.6",
        executable="/usr/bin/python3.6",
        flags={
            "always-copy": False,
            "system-site-packages": False,
            "no-pip": False,
            "no-setuptools": False,
        },
        prompt="simple-project-py3.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) / f"{venv_name}-py3.6"
    assert env.base == Path("/prefix")
Esempio n. 12
0
def test_uploader_properly_handles_403_errors(http):
    http.register_uri(http.POST,
                      "https://foo.com",
                      status=403,
                      body="Unauthorized")
    uploader = Uploader(Factory().create_poetry(project("simple_project")),
                        NullIO())

    with pytest.raises(UploadError) as e:
        uploader.upload("https://foo.com")

    assert "HTTP Error 403: Forbidden" == str(e.value)
Esempio n. 13
0
def test_uploader_registers_for_appropriate_400_errors(mocker, http):
    register = mocker.patch("poetry.publishing.uploader.Uploader._register")
    http.register_uri(http.POST,
                      "https://foo.com",
                      status=400,
                      body="No package was ever registered")
    uploader = Uploader(Factory().create_poetry(project("simple_project")),
                        NullIO())

    with pytest.raises(UploadError):
        uploader.upload("https://foo.com")

    assert 1 == register.call_count
Esempio n. 14
0
def test_authenticator_uses_username_only_credentials(
    mock_config: Config,
    mock_remote: None,
    http: type[httpretty.httpretty],
    with_simple_keyring: None,
):
    authenticator = Authenticator(mock_config, NullIO())
    authenticator.request("get",
                          "https://[email protected]/files/foo-0.1.0.tar.gz")

    request = http.last_request()

    assert request.headers["Authorization"] == "Basic Zm9vMDAxOg=="
Esempio n. 15
0
def test_uploader_properly_handles_301_redirects(http):
    http.register_uri(http.POST,
                      "https://foo.com",
                      status=301,
                      body="Redirect")
    uploader = Uploader(Factory().create_poetry(project("simple_project")),
                        NullIO())

    with pytest.raises(UploadError) as e:
        uploader.upload("https://foo.com")

    assert "Redirects are not supported. Is the URL missing a trailing slash?" == str(
        e.value)
Esempio n. 16
0
def test_requirement_source_type_url():
    installer = PipInstaller(NullEnv(), NullIO(), Pool())

    foo = Package(
        "foo",
        "0.0.0",
        source_type="url",
        source_url="https://somewhere.com/releases/foo-1.0.0.tar.gz",
    )

    result = installer.requirement(foo, formatted=True)
    expected = f"{foo.source_url}#egg={foo.name}"

    assert result == expected
Esempio n. 17
0
def test_authenticator_uses_password_only_credentials(config, mock_remote, http):
    config.merge(
        {
            "repositories": {"foo": {"url": "https://foo.bar/simple/"}},
            "http-basic": {"foo": {"username": "******", "password": "******"}},
        }
    )

    authenticator = Authenticator(config, NullIO())
    authenticator.request("get", "https://:[email protected]/files/foo-0.1.0.tar.gz")

    request = http.last_request()

    assert "Basic OmJhcjAwMg==" == request.headers["Authorization"]
Esempio n. 18
0
def test_create_venv_fails_if_current_python_version_is_not_supported(
        manager: EnvManager, poetry: Poetry):
    if "VIRTUAL_ENV" in os.environ:
        del os.environ["VIRTUAL_ENV"]

    manager.create_venv(NullIO())

    current_version = Version.parse(".".join(
        str(c) for c in sys.version_info[:3]))
    next_version = ".".join(
        str(c) for c in (current_version.major, current_version.minor + 1, 0))
    package_version = "~" + next_version
    poetry.package.python_versions = package_version

    with pytest.raises(InvalidCurrentPythonVersionError) as e:
        manager.create_venv(NullIO())

    expected_message = (
        f"Current Python version ({current_version}) is not allowed by the project"
        f' ({package_version}).\nPlease change python executable via the "env use"'
        " command.")

    assert expected_message == str(e.value)
Esempio n. 19
0
def test_authenticator_git_repositories(
    config: Config,
    mock_remote: None,
    http: type[httpretty.httpretty],
    with_simple_keyring: None,
    dummy_keyring: DummyBackend,
):
    config.merge({
        "repositories": {
            "one": {
                "url": "https://foo.bar/org/one.git"
            },
            "two": {
                "url": "https://foo.bar/org/two.git"
            },
        },
        "http-basic": {
            "one": {
                "username": "******",
                "password": "******"
            },
            "two": {
                "username": "******",
                "password": "******"
            },
        },
    })

    authenticator = Authenticator(config, NullIO())

    one = authenticator.get_credentials_for_git_url(
        "https://foo.bar/org/one.git")
    assert one.username == "foo"
    assert one.password == "bar"

    two = authenticator.get_credentials_for_git_url(
        "https://foo.bar/org/two.git")
    assert two.username == "baz"
    assert two.password == "qux"

    two_ssh = authenticator.get_credentials_for_git_url(
        "ssh://[email protected]/org/two.git")
    assert not two_ssh.username
    assert not two_ssh.password

    three = authenticator.get_credentials_for_git_url(
        "https://foo.bar/org/three.git")
    assert not three.username
    assert not three.password
Esempio n. 20
0
def test_activate_does_not_recreate_when_switching_minor(
    tmp_dir: str,
    manager: EnvManager,
    poetry: "Poetry",
    config: "Config",
    mocker: "MockerFixture",
):
    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, f"{venv_name}-py3.7"))
    os.mkdir(os.path.join(tmp_dir, f"{venv_name}-py3.6"))

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

    mocker.patch(
        "subprocess.check_output",
        side_effect=check_output_wrapper(Version.parse("3.6.6")),
    )
    mocker.patch(
        "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=EnvManager.remove_venv
    )

    env = manager.activate("python3.6", 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) / f"{venv_name}-py3.6"
    assert env.base == Path("/prefix")
    assert (Path(tmp_dir) / f"{venv_name}-py3.6").exists()
Esempio n. 21
0
def test_builder_should_execute_build_scripts(
        mocker: MockerFixture, extended_without_setup_poetry: Poetry,
        tmp_dir: str):
    env = MockEnv(path=Path(tmp_dir) / "foo")
    mocker.patch("poetry.masonry.builders.editable.build_environment"
                 ).return_value.__enter__.return_value = env

    builder = EditableBuilder(extended_without_setup_poetry, env, NullIO())

    builder.build()

    assert [[
        "python",
        str(extended_without_setup_poetry.file.parent / "build.py")
    ]] == env.executed
Esempio n. 22
0
def test_publish_uses_token_if_it_exists(fixture_dir, mocker, config):
    uploader_auth = mocker.patch("poetry.publishing.uploader.Uploader.auth")
    uploader_upload = mocker.patch("poetry.publishing.uploader.Uploader.upload")
    poetry = Factory().create_poetry(fixture_dir("sample_project"))
    poetry._config = config
    poetry.config.merge({"pypi-token": {"pypi": "my-token"}})
    publisher = Publisher(poetry, NullIO())

    publisher.publish(None, None, None)

    assert [("__token__", "my-token")] == uploader_auth.call_args
    assert [
        ("https://upload.pypi.org/legacy/",),
        {"cert": None, "client_cert": None, "dry_run": False},
    ] == uploader_upload.call_args
Esempio n. 23
0
def test_publish_read_from_environment_variable(fixture_dir, environ, mocker, config):
    os.environ["POETRY_REPOSITORIES_FOO_URL"] = "https://foo.bar"
    os.environ["POETRY_HTTP_BASIC_FOO_USERNAME"] = "******"
    os.environ["POETRY_HTTP_BASIC_FOO_PASSWORD"] = "******"
    uploader_auth = mocker.patch("poetry.publishing.uploader.Uploader.auth")
    uploader_upload = mocker.patch("poetry.publishing.uploader.Uploader.upload")
    poetry = Factory().create_poetry(fixture_dir("sample_project"))
    publisher = Publisher(poetry, NullIO())

    publisher.publish("foo", None, None)

    assert [("bar", "baz")] == uploader_auth.call_args
    assert [
        ("https://foo.bar",),
        {"cert": None, "client_cert": None, "dry_run": False},
    ] == uploader_upload.call_args
Esempio n. 24
0
def test_authenticator_uses_empty_strings_as_default_password(
    config, mock_remote, http, with_simple_keyring
):
    config.merge(
        {
            "repositories": {"foo": {"url": "https://foo.bar/simple/"}},
            "http-basic": {"foo": {"username": "******"}},
        }
    )

    authenticator = Authenticator(config, NullIO())
    authenticator.request("get", "https://foo.bar/files/foo-0.1.0.tar.gz")

    request = http.last_request()

    assert "Basic YmFyOg==" == request.headers["Authorization"]
Esempio n. 25
0
def test_authenticator_request_raises_exception_when_attempts_exhausted(
        mocker, config, http):
    sleep = mocker.patch("time.sleep")
    sdist_uri = "https://foo.bar/files/{}/foo-0.1.0.tar.gz".format(
        str(uuid.uuid4()))

    def callback(*_, **__):
        raise requests.exceptions.ConnectionError(str(uuid.uuid4()))

    httpretty.register_uri(httpretty.GET, sdist_uri, body=callback)
    authenticator = Authenticator(config, NullIO())

    with pytest.raises(requests.exceptions.ConnectionError):
        authenticator.request("get", sdist_uri)

    assert sleep.call_count == 5
Esempio n. 26
0
def test_authenticator_uses_credentials_from_config_if_not_provided(
    config: "Config", mock_remote: None, http: Type[httpretty.httpretty]
):
    config.merge(
        {
            "repositories": {"foo": {"url": "https://foo.bar/simple/"}},
            "http-basic": {"foo": {"username": "******", "password": "******"}},
        }
    )

    authenticator = Authenticator(config, NullIO())
    authenticator.request("get", "https://foo.bar/files/foo-0.1.0.tar.gz")

    request = http.last_request()

    assert request.headers["Authorization"] == "Basic YmFyOmJheg=="
Esempio n. 27
0
def test_authenticator_request_raises_exception_when_attempts_exhausted(
    mocker: "MockerFixture", config: "Config", http: Type[httpretty.httpretty]
):
    sleep = mocker.patch("time.sleep")
    sdist_uri = f"https://foo.bar/files/{uuid.uuid4()!s}/foo-0.1.0.tar.gz"

    def callback(*_: Any, **___: Any) -> None:
        raise requests.exceptions.ConnectionError(str(uuid.uuid4()))

    httpretty.register_uri(httpretty.GET, sdist_uri, body=callback)
    authenticator = Authenticator(config, NullIO())

    with pytest.raises(requests.exceptions.ConnectionError):
        authenticator.request("get", sdist_uri)

    assert sleep.call_count == 5
Esempio n. 28
0
def test_authenticator_uses_empty_strings_as_default_username(
    config: "Config", mock_remote: None, http: Type[httpretty.httpretty]
):
    config.merge(
        {
            "repositories": {"foo": {"url": "https://foo.bar/simple/"}},
            "http-basic": {"foo": {"username": None, "password": "******"}},
        }
    )

    authenticator = Authenticator(config, NullIO())
    authenticator.request("get", "https://foo.bar/files/foo-0.1.0.tar.gz")

    request = http.last_request()

    assert request.headers["Authorization"] == "Basic OmJhcg=="
Esempio n. 29
0
def test_builder_falls_back_on_setup_and_pip_for_packages_with_build_scripts(
        extended_poetry, tmp_dir):
    env = MockEnv(path=Path(tmp_dir) / "foo")
    builder = EditableBuilder(extended_poetry, env, NullIO())

    builder.build()

    assert [[
        "python",
        "-m",
        "pip",
        "install",
        "-e",
        str(extended_poetry.file.parent),
        "--no-deps",
    ]] == env.executed
Esempio n. 30
0
def test_authenticator_uses_url_provided_credentials(
    config: Config, mock_remote: None, http: type[httpretty.httpretty]
):
    config.merge(
        {
            "repositories": {"foo": {"url": "https://foo.bar/simple/"}},
            "http-basic": {"foo": {"username": "******", "password": "******"}},
        }
    )

    authenticator = Authenticator(config, NullIO())
    authenticator.request("get", "https://*****:*****@foo.bar/files/foo-0.1.0.tar.gz")

    request = http.last_request()

    assert request.headers["Authorization"] == "Basic Zm9vMDAxOmJhcjAwMg=="