From 1051e5fd446f06aaeb348371f13a998bb85b87ed Mon Sep 17 00:00:00 2001 From: Arun Babu Neelicattu Date: Tue, 20 Oct 2020 01:42:39 +0200 Subject: [PATCH] pool: ensure sources are prioritised over PyPI When a project specifies non default sources, PyPI gets added as the default source. This will prioritise packages available in PyPI when the package exists in both index. This change ensures that PyPI is only used as a default when no other sources are provided. Resolves: #1677 #2564 #3238 --- poetry/factory.py | 8 ++- .../with_non_default_source/README.rst | 2 + .../with_non_default_source/pyproject.toml | 60 +++++++++++++++++++ tests/test_factory.py | 27 +++++++++ 4 files changed, 94 insertions(+), 3 deletions(-) create mode 100644 tests/fixtures/with_non_default_source/README.rst create mode 100644 tests/fixtures/with_non_default_source/pyproject.toml diff --git a/poetry/factory.py b/poetry/factory.py index fd863ba5991..e6459cc51c3 100755 --- a/poetry/factory.py +++ b/poetry/factory.py @@ -70,7 +70,8 @@ def create_poetry( ) # Configuring sources - for source in poetry.local_config.get("source", []): + sources = poetry.local_config.get("source", []) + for source in sources: repository = self.create_legacy_repository(source, config) is_default = source.get("default", False) is_secondary = source.get("secondary", False) @@ -88,9 +89,10 @@ def create_poetry( 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 + # but only if we have no other default sourced if not poetry.pool.has_default(): - poetry.pool.add_repository(PyPiRepository(), True) + has_sources = bool(sources) + poetry.pool.add_repository(PyPiRepository(), not has_sources, has_sources) else: if io.is_debug(): io.write_line("Deactivating the PyPI repository") diff --git a/tests/fixtures/with_non_default_source/README.rst b/tests/fixtures/with_non_default_source/README.rst new file mode 100644 index 00000000000..f7fe15470f9 --- /dev/null +++ b/tests/fixtures/with_non_default_source/README.rst @@ -0,0 +1,2 @@ +My Package +========== diff --git a/tests/fixtures/with_non_default_source/pyproject.toml b/tests/fixtures/with_non_default_source/pyproject.toml new file mode 100644 index 00000000000..d4d127de7e1 --- /dev/null +++ b/tests/fixtures/with_non_default_source/pyproject.toml @@ -0,0 +1,60 @@ +[tool.poetry] +name = "my-package" +version = "1.2.3" +description = "Some description." +authors = [ + "Sébastien Eustace " +] +license = "MIT" + +readme = "README.rst" + +homepage = "https://python-poetry.org" +repository = "https://github.com/python-poetry/poetry" +documentation = "https://python-poetry.org/docs" + +keywords = ["packaging", "dependency", "poetry"] + +classifiers = [ + "Topic :: Software Development :: Build Tools", + "Topic :: Software Development :: Libraries :: Python Modules" +] + +# Requirements +[tool.poetry.dependencies] +python = "~2.7 || ^3.6" +cleo = "^0.6" +pendulum = { git = "https://github.com/sdispater/pendulum.git", branch = "2.0" } +requests = { version = "^2.18", optional = true, extras=[ "security" ] } +pathlib2 = { version = "^2.2", python = "~2.7" } + +orator = { version = "^0.9", optional = true } + +# File dependency +demo = { path = "../distributions/demo-0.1.0-py2.py3-none-any.whl" } + +# Dir dependency with setup.py +my-package = { path = "../project_with_setup/" } + +# Dir dependency with pyproject.toml +simple-project = { path = "../simple_project/" } + + +[tool.poetry.extras] +db = [ "orator" ] + +[tool.poetry.dev-dependencies] +pytest = "~3.4" + + +[tool.poetry.scripts] +my-script = "my_package:main" + + +[tool.poetry.plugins."blogtool.parsers"] +".rst" = "some_module::SomeClass" + + +[[tool.poetry.source]] +name = "foo" +url = "https://foo.bar/simple/" diff --git a/tests/test_factory.py b/tests/test_factory.py index d7758e8deaa..b2c232b20e7 100644 --- a/tests/test_factory.py +++ b/tests/test_factory.py @@ -6,6 +6,8 @@ from poetry.core.toml.file import TOMLFile from poetry.factory import Factory +from poetry.repositories.legacy_repository import LegacyRepository +from poetry.repositories.pypi_repository import PyPiRepository from poetry.utils._compat import PY2 from poetry.utils._compat import Path @@ -150,6 +152,31 @@ def test_poetry_with_default_source(): assert 1 == len(poetry.pool.repositories) +def test_poetry_with_non_default_source(): + poetry = Factory().create_poetry(fixtures_dir / "with_non_default_source") + + assert len(poetry.pool.repositories) == 2 + + assert not poetry.pool.has_default() + + assert poetry.pool.repositories[0].name == "foo" + assert isinstance(poetry.pool.repositories[0], LegacyRepository) + + assert poetry.pool.repositories[1].name == "PyPI" + assert isinstance(poetry.pool.repositories[1], PyPiRepository) + + +def test_poetry_with_no_default_source(): + poetry = Factory().create_poetry(fixtures_dir / "sample_project") + + assert len(poetry.pool.repositories) == 1 + + assert poetry.pool.has_default() + + assert poetry.pool.repositories[0].name == "PyPI" + assert isinstance(poetry.pool.repositories[0], PyPiRepository) + + def test_poetry_with_two_default_sources(): with pytest.raises(ValueError) as e: Factory().create_poetry(fixtures_dir / "with_two_default_sources")