Commit 4d05c156 by Yannick PÉROUX Committed by GitHub

Add --source option to "poetry add" (#1912)

* Add --source option to 'poetry add'

* Add tests for 'poetry add --source'
parent 65ab92de
...@@ -33,6 +33,12 @@ class AddCommand(EnvCommand, InitCommand): ...@@ -33,6 +33,12 @@ class AddCommand(EnvCommand, InitCommand):
"Platforms for which the dependency must be installed.", "Platforms for which the dependency must be installed.",
flag=False, flag=False,
), ),
option(
"source",
None,
"Name of the source to use to install the package.",
flag=False,
),
option("allow-prereleases", None, "Accept prereleases."), option("allow-prereleases", None, "Accept prereleases."),
option( option(
"dry-run", "dry-run",
...@@ -86,7 +92,9 @@ If you do not specify a version constraint, poetry will choose a suitable one ba ...@@ -86,7 +92,9 @@ If you do not specify a version constraint, poetry will choose a suitable one ba
raise ValueError("Package {} is already present".format(name)) raise ValueError("Package {} is already present".format(name))
requirements = self._determine_requirements( requirements = self._determine_requirements(
packages, allow_prereleases=self.option("allow-prereleases") packages,
allow_prereleases=self.option("allow-prereleases"),
source=self.option("source"),
) )
for _constraint in requirements: for _constraint in requirements:
...@@ -123,6 +131,9 @@ If you do not specify a version constraint, poetry will choose a suitable one ba ...@@ -123,6 +131,9 @@ If you do not specify a version constraint, poetry will choose a suitable one ba
if self.option("platform"): if self.option("platform"):
constraint["platform"] = self.option("platform") constraint["platform"] = self.option("platform")
if self.option("source"):
constraint["source"] = self.option("source")
if len(constraint) == 1 and "version" in constraint: if len(constraint) == 1 and "version" in constraint:
constraint = constraint["version"] constraint = constraint["version"]
......
...@@ -204,7 +204,7 @@ The <c1>init</c1> command creates a basic <comment>pyproject.toml</> file in the ...@@ -204,7 +204,7 @@ The <c1>init</c1> command creates a basic <comment>pyproject.toml</> file in the
f.write(content) f.write(content)
def _determine_requirements( def _determine_requirements(
self, requires, allow_prereleases=False self, requires, allow_prereleases=False, source=None
): # type: (List[str], bool) -> List[Dict[str, str]] ): # type: (List[str], bool) -> List[Dict[str, str]]
if not requires: if not requires:
requires = [] requires = []
...@@ -300,7 +300,9 @@ The <c1>init</c1> command creates a basic <comment>pyproject.toml</> file in the ...@@ -300,7 +300,9 @@ The <c1>init</c1> command creates a basic <comment>pyproject.toml</> file in the
elif "version" not in requirement: elif "version" not in requirement:
# determine the best version automatically # determine the best version automatically
name, version = self._find_best_version_for_package( name, version = self._find_best_version_for_package(
requirement["name"], allow_prereleases=allow_prereleases requirement["name"],
allow_prereleases=allow_prereleases,
source=source,
) )
requirement["version"] = version requirement["version"] = version
requirement["name"] = name requirement["name"] = name
...@@ -315,6 +317,7 @@ The <c1>init</c1> command creates a basic <comment>pyproject.toml</> file in the ...@@ -315,6 +317,7 @@ The <c1>init</c1> command creates a basic <comment>pyproject.toml</> file in the
requirement["name"], requirement["name"],
requirement["version"], requirement["version"],
allow_prereleases=allow_prereleases, allow_prereleases=allow_prereleases,
source=source,
) )
requirement["name"] = name requirement["name"] = name
...@@ -324,13 +327,13 @@ The <c1>init</c1> command creates a basic <comment>pyproject.toml</> file in the ...@@ -324,13 +327,13 @@ The <c1>init</c1> command creates a basic <comment>pyproject.toml</> file in the
return result return result
def _find_best_version_for_package( def _find_best_version_for_package(
self, name, required_version=None, allow_prereleases=False self, name, required_version=None, allow_prereleases=False, source=None
): # type: (...) -> Tuple[str, str] ): # type: (...) -> Tuple[str, str]
from poetry.version.version_selector import VersionSelector from poetry.version.version_selector import VersionSelector
selector = VersionSelector(self._get_pool()) selector = VersionSelector(self._get_pool())
package = selector.find_best_candidate( package = selector.find_best_candidate(
name, required_version, allow_prereleases=allow_prereleases name, required_version, allow_prereleases=allow_prereleases, source=source
) )
if not package: if not package:
......
...@@ -15,6 +15,7 @@ class VersionSelector(object): ...@@ -15,6 +15,7 @@ class VersionSelector(object):
package_name, # type: str package_name, # type: str
target_package_version=None, # type: Union[str, None] target_package_version=None, # type: Union[str, None]
allow_prereleases=False, # type: bool allow_prereleases=False, # type: bool
source=None, # type: str
): # type: (...) -> Union[Package, bool] ): # type: (...) -> Union[Package, bool]
""" """
Given a package name and optional version, Given a package name and optional version,
...@@ -26,7 +27,7 @@ class VersionSelector(object): ...@@ -26,7 +27,7 @@ class VersionSelector(object):
constraint = parse_constraint("*") constraint = parse_constraint("*")
candidates = self._pool.find_packages( candidates = self._pool.find_packages(
package_name, constraint, allow_prereleases=True package_name, constraint, allow_prereleases=True, repository=source
) )
only_prereleases = all([c.version.is_prerelease() for c in candidates]) only_prereleases = all([c.version.is_prerelease() for c in candidates])
......
...@@ -4,6 +4,8 @@ import pytest ...@@ -4,6 +4,8 @@ import pytest
from cleo.testers import CommandTester from cleo.testers import CommandTester
from poetry.repositories.legacy_repository import LegacyRepository
from poetry.semver import Version
from poetry.utils._compat import Path from poetry.utils._compat import Path
from tests.helpers import get_dependency from tests.helpers import get_dependency
from tests.helpers import get_package from tests.helpers import get_package
...@@ -634,6 +636,72 @@ Package operations: 1 install, 0 updates, 0 removals ...@@ -634,6 +636,72 @@ Package operations: 1 install, 0 updates, 0 removals
} }
def test_add_constraint_with_source(app, poetry, installer):
repo = LegacyRepository(name="my-index", url="https://my-index.fake")
repo.add_package(get_package("cachy", "0.2.0"))
repo._cache.store("matches").put("cachy:0.2.0", [Version.parse("0.2.0")], 5)
poetry.pool.add_repository(repo)
command = app.find("add")
tester = CommandTester(command)
tester.execute("cachy=0.2.0 --source my-index")
expected = """\
Updating dependencies
Resolving dependencies...
Writing lock file
Package operations: 1 install, 0 updates, 0 removals
- Installing cachy (0.2.0)
"""
assert expected == tester.io.fetch_output()
assert len(installer.installs) == 1
content = app.poetry.file.read()["tool"]["poetry"]
assert "cachy" in content["dependencies"]
assert content["dependencies"]["cachy"] == {
"version": "0.2.0",
"source": "my-index",
}
def test_add_constraint_with_source_that_does_not_exist(app):
command = app.find("add")
tester = CommandTester(command)
with pytest.raises(ValueError) as e:
tester.execute("foo --source i-dont-exist")
assert 'Repository "i-dont-exist" does not exist.' == str(e.value)
def test_add_constraint_not_found_with_source(app, poetry, mocker):
repo = LegacyRepository(name="my-index", url="https://my-index.fake")
mocker.patch.object(repo, "find_packages", return_value=[])
poetry.pool.add_repository(repo)
pypi = poetry.pool.repositories[0]
pypi.add_package(get_package("cachy", "0.2.0"))
command = app.find("add")
tester = CommandTester(command)
with pytest.raises(ValueError) as e:
tester.execute("cachy --source my-index")
assert "Could not find a matching version of package cachy" == str(e.value)
def test_add_to_section_that_does_no_exist_yet(app, repo, installer): def test_add_to_section_that_does_no_exist_yet(app, repo, installer):
command = app.find("add") command = app.find("add")
tester = CommandTester(command) tester = CommandTester(command)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment