From a3c5cf7c9559dbb0b0372aa2e30b5ce3f2a849af Mon Sep 17 00:00:00 2001 From: Tom Rochette Date: Mon, 26 Apr 2021 11:29:36 -0400 Subject: [PATCH] Add PyPI registry correctly to pool depending on other sources (#3406) In the event where we defined sources that were set as secondary = True, we would end up with PyPI being after this source when it should have acted as default in that case. The main issue stems from the fact that it's not because you have sources configured that PyPI should not be a default. Instead, PyPI should be default if there are no sources with secondary = False and not default if there are sources with secondary = True. --- poetry/factory.py | 13 +++-- poetry/repositories/pool.py | 5 ++ .../pyproject.toml | 24 ++++++++ .../pyproject.toml | 23 ++++++++ .../pyproject.toml | 19 ++++++ tests/test_factory.py | 58 +++++++++++++++++++ 6 files changed, 136 insertions(+), 6 deletions(-) create mode 100644 tests/fixtures/with_non_default_multiple_secondary_sources/pyproject.toml create mode 100644 tests/fixtures/with_non_default_multiple_sources/pyproject.toml create mode 100644 tests/fixtures/with_non_default_secondary_source/pyproject.toml diff --git a/poetry/factory.py b/poetry/factory.py index 36078bed1e5..144bfe35871 100644 --- a/poetry/factory.py +++ b/poetry/factory.py @@ -153,14 +153,15 @@ def configure_sources( poetry.pool.add_repository(repository, is_default, secondary=is_secondary) - # Always put PyPI last to prefer private repositories - # but only if we have no other default source - if not poetry.pool.has_default(): - has_sources = bool(sources) - poetry.pool.add_repository(PyPiRepository(), not has_sources, has_sources) - else: + # Put PyPI last to prefer private repositories + # unless we have no default source AND no primary sources + # (default = false, secondary = false) + if poetry.pool.has_default(): if io.is_debug(): io.write_line("Deactivating the PyPI repository") + else: + default = not poetry.pool.has_primary_repositories() + poetry.pool.add_repository(PyPiRepository(), default, not default) @classmethod def create_legacy_repository( diff --git a/poetry/repositories/pool.py b/poetry/repositories/pool.py index 251ff92506b..b57ba155ec2 100644 --- a/poetry/repositories/pool.py +++ b/poetry/repositories/pool.py @@ -25,6 +25,7 @@ def __init__( self._lookup: Dict[str, int] = {} self._repositories: List[Repository] = [] self._default = False + self._has_primary_repositories = False self._secondary_start_idx = None for repository in repositories: @@ -41,6 +42,9 @@ def repositories(self) -> List[Repository]: def has_default(self) -> bool: return self._default + def has_primary_repositories(self) -> bool: + return self._has_primary_repositories + def has_repository(self, name: str) -> bool: name = name.lower() if name is not None else None @@ -84,6 +88,7 @@ def add_repository( self._repositories.append(repository) self._lookup[repository_name] = len(self._repositories) - 1 else: + self._has_primary_repositories = True if self._secondary_start_idx is None: self._repositories.append(repository) self._lookup[repository_name] = len(self._repositories) - 1 diff --git a/tests/fixtures/with_non_default_multiple_secondary_sources/pyproject.toml b/tests/fixtures/with_non_default_multiple_secondary_sources/pyproject.toml new file mode 100644 index 00000000000..933bee96912 --- /dev/null +++ b/tests/fixtures/with_non_default_multiple_secondary_sources/pyproject.toml @@ -0,0 +1,24 @@ +[tool.poetry] +name = "my-package" +version = "1.2.3" +description = "Some description." +authors = [ + "Your Name " +] +license = "MIT" + +# Requirements +[tool.poetry.dependencies] +python = "~2.7 || ^3.6" + +[tool.poetry.dev-dependencies] + +[[tool.poetry.source]] +name = "foo" +url = "https://foo.bar/simple/" +secondary = true + +[[tool.poetry.source]] +name = "bar" +url = "https://bar.baz/simple/" +secondary = true diff --git a/tests/fixtures/with_non_default_multiple_sources/pyproject.toml b/tests/fixtures/with_non_default_multiple_sources/pyproject.toml new file mode 100644 index 00000000000..6cacb602e8b --- /dev/null +++ b/tests/fixtures/with_non_default_multiple_sources/pyproject.toml @@ -0,0 +1,23 @@ +[tool.poetry] +name = "my-package" +version = "1.2.3" +description = "Some description." +authors = [ + "Your Name " +] +license = "MIT" + +# Requirements +[tool.poetry.dependencies] +python = "~2.7 || ^3.6" + +[tool.poetry.dev-dependencies] + +[[tool.poetry.source]] +name = "foo" +url = "https://foo.bar/simple/" +secondary = true + +[[tool.poetry.source]] +name = "bar" +url = "https://bar.baz/simple/" diff --git a/tests/fixtures/with_non_default_secondary_source/pyproject.toml b/tests/fixtures/with_non_default_secondary_source/pyproject.toml new file mode 100644 index 00000000000..453e3f9747f --- /dev/null +++ b/tests/fixtures/with_non_default_secondary_source/pyproject.toml @@ -0,0 +1,19 @@ +[tool.poetry] +name = "my-package" +version = "1.2.3" +description = "Some description." +authors = [ + "Your Name " +] +license = "MIT" + +# Requirements +[tool.poetry.dependencies] +python = "~2.7 || ^3.6" + +[tool.poetry.dev-dependencies] + +[[tool.poetry.source]] +name = "foo" +url = "https://foo.bar/simple/" +secondary = true diff --git a/tests/test_factory.py b/tests/test_factory.py index 13a0437174c..e9a9a9a5994 100644 --- a/tests/test_factory.py +++ b/tests/test_factory.py @@ -176,6 +176,64 @@ def test_poetry_with_non_default_source(): assert isinstance(poetry.pool.repositories[1], PyPiRepository) +def test_poetry_with_non_default_secondary_source(): + poetry = Factory().create_poetry(fixtures_dir / "with_non_default_secondary_source") + + assert len(poetry.pool.repositories) == 2 + + assert poetry.pool.has_default() + + repository = poetry.pool.repositories[0] + assert repository.name == "PyPI" + assert isinstance(repository, PyPiRepository) + + repository = poetry.pool.repositories[1] + assert repository.name == "foo" + assert isinstance(repository, LegacyRepository) + + +def test_poetry_with_non_default_multiple_secondary_sources(): + poetry = Factory().create_poetry( + fixtures_dir / "with_non_default_multiple_secondary_sources" + ) + + assert len(poetry.pool.repositories) == 3 + + assert poetry.pool.has_default() + + repository = poetry.pool.repositories[0] + assert repository.name == "PyPI" + assert isinstance(repository, PyPiRepository) + + repository = poetry.pool.repositories[1] + assert repository.name == "foo" + assert isinstance(repository, LegacyRepository) + + repository = poetry.pool.repositories[2] + assert repository.name == "bar" + assert isinstance(repository, LegacyRepository) + + +def test_poetry_with_non_default_multiple_sources(): + poetry = Factory().create_poetry(fixtures_dir / "with_non_default_multiple_sources") + + assert len(poetry.pool.repositories) == 3 + + assert not poetry.pool.has_default() + + repository = poetry.pool.repositories[0] + assert repository.name == "bar" + assert isinstance(repository, LegacyRepository) + + repository = poetry.pool.repositories[1] + assert repository.name == "foo" + assert isinstance(repository, LegacyRepository) + + repository = poetry.pool.repositories[2] + assert repository.name == "PyPI" + assert isinstance(repository, PyPiRepository) + + def test_poetry_with_no_default_source(): poetry = Factory().create_poetry(fixtures_dir / "sample_project")