Skip to content

Commit

Permalink
Add --source option to "poetry add" (#1912)
Browse files Browse the repository at this point in the history
* Add --source option to 'poetry add'

* Add tests for 'poetry add --source'
  • Loading branch information
k4nar authored Jan 31, 2020
1 parent 65ab92d commit 4d05c15
Show file tree
Hide file tree
Showing 4 changed files with 89 additions and 6 deletions.
13 changes: 12 additions & 1 deletion poetry/console/commands/add.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,12 @@ class AddCommand(EnvCommand, InitCommand):
"Platforms for which the dependency must be installed.",
flag=False,
),
option(
"source",
None,
"Name of the source to use to install the package.",
flag=False,
),
option("allow-prereleases", None, "Accept prereleases."),
option(
"dry-run",
Expand Down Expand Up @@ -86,7 +92,9 @@ def handle(self):
raise ValueError("Package {} is already present".format(name))

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:
Expand Down Expand Up @@ -123,6 +131,9 @@ def handle(self):
if 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:
constraint = constraint["version"]

Expand Down
11 changes: 7 additions & 4 deletions poetry/console/commands/init.py
Original file line number Diff line number Diff line change
Expand Up @@ -204,7 +204,7 @@ def handle(self):
f.write(content)

def _determine_requirements(
self, requires, allow_prereleases=False
self, requires, allow_prereleases=False, source=None
): # type: (List[str], bool) -> List[Dict[str, str]]
if not requires:
requires = []
Expand Down Expand Up @@ -300,7 +300,9 @@ def _determine_requirements(
elif "version" not in requirement:
# determine the best version automatically
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["name"] = name
Expand All @@ -315,6 +317,7 @@ def _determine_requirements(
requirement["name"],
requirement["version"],
allow_prereleases=allow_prereleases,
source=source,
)

requirement["name"] = name
Expand All @@ -324,13 +327,13 @@ def _determine_requirements(
return result

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]
from poetry.version.version_selector import VersionSelector

selector = VersionSelector(self._get_pool())
package = selector.find_best_candidate(
name, required_version, allow_prereleases=allow_prereleases
name, required_version, allow_prereleases=allow_prereleases, source=source
)

if not package:
Expand Down
3 changes: 2 additions & 1 deletion poetry/version/version_selector.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ def find_best_candidate(
package_name, # type: str
target_package_version=None, # type: Union[str, None]
allow_prereleases=False, # type: bool
source=None, # type: str
): # type: (...) -> Union[Package, bool]
"""
Given a package name and optional version,
Expand All @@ -26,7 +27,7 @@ def find_best_candidate(
constraint = parse_constraint("*")

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])

Expand Down
68 changes: 68 additions & 0 deletions tests/console/commands/test_add.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@

from cleo.testers import CommandTester

from poetry.repositories.legacy_repository import LegacyRepository
from poetry.semver import Version
from poetry.utils._compat import Path
from tests.helpers import get_dependency
from tests.helpers import get_package
Expand Down Expand Up @@ -634,6 +636,72 @@ def test_add_constraint_with_platform(app, repo, installer):
}


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):
command = app.find("add")
tester = CommandTester(command)
Expand Down

0 comments on commit 4d05c15

Please sign in to comment.