Commit 55ebb9cd by Sébastien Eustace

Fix and improve handling of extras while resolving dependencies

parent dfa5c0f6
...@@ -461,7 +461,7 @@ six = ">=1.0.0,<2.0.0" ...@@ -461,7 +461,7 @@ six = ">=1.0.0,<2.0.0"
[[package]] [[package]]
name = "more-itertools" name = "more-itertools"
version = "8.3.0" version = "8.4.0"
description = "More routines for operating on iterables, beyond itertools" description = "More routines for operating on iterables, beyond itertools"
category = "dev" category = "dev"
optional = false optional = false
...@@ -469,7 +469,7 @@ python-versions = ">=3.5" ...@@ -469,7 +469,7 @@ python-versions = ">=3.5"
[[package]] [[package]]
name = "more-itertools" name = "more-itertools"
version = "8.4.0" version = "8.5.0"
description = "More routines for operating on iterables, beyond itertools" description = "More routines for operating on iterables, beyond itertools"
category = "dev" category = "dev"
optional = false optional = false
...@@ -561,8 +561,8 @@ importlib-metadata = {version = ">=0.12", markers = "python_version < \"3.8\""} ...@@ -561,8 +561,8 @@ importlib-metadata = {version = ">=0.12", markers = "python_version < \"3.8\""}
[[package]] [[package]]
name = "poetry-core" name = "poetry-core"
version = "1.0.0a9" version = "1.0.0b1"
description = "Core utilities for Poetry" description = "Poetry PEP 517 Build Backend"
category = "main" category = "main"
optional = false optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
...@@ -984,7 +984,7 @@ contextlib2 = {version = "*", markers = "python_version < \"3.4\""} ...@@ -984,7 +984,7 @@ contextlib2 = {version = "*", markers = "python_version < \"3.4\""}
[metadata] [metadata]
lock-version = "1.1" lock-version = "1.1"
python-versions = "~2.7 || ^3.5" python-versions = "~2.7 || ^3.5"
content-hash = "9528141e0eb24000c6f245065820732b3977d1c7d14c14fbcedf77e91c4a3e68" content-hash = "062aef66c1c37dce14fcb2a66841afe97937ce9150136ff8dfa45e43d796821f"
[metadata.files] [metadata.files]
appdirs = [ appdirs = [
...@@ -1217,10 +1217,10 @@ more-itertools = [ ...@@ -1217,10 +1217,10 @@ more-itertools = [
{file = "more-itertools-5.0.0.tar.gz", hash = "sha256:38a936c0a6d98a38bcc2d03fdaaedaba9f412879461dd2ceff8d37564d6522e4"}, {file = "more-itertools-5.0.0.tar.gz", hash = "sha256:38a936c0a6d98a38bcc2d03fdaaedaba9f412879461dd2ceff8d37564d6522e4"},
{file = "more_itertools-5.0.0-py2-none-any.whl", hash = "sha256:c0a5785b1109a6bd7fac76d6837fd1feca158e54e521ccd2ae8bfe393cc9d4fc"}, {file = "more_itertools-5.0.0-py2-none-any.whl", hash = "sha256:c0a5785b1109a6bd7fac76d6837fd1feca158e54e521ccd2ae8bfe393cc9d4fc"},
{file = "more_itertools-5.0.0-py3-none-any.whl", hash = "sha256:fe7a7cae1ccb57d33952113ff4fa1bc5f879963600ed74918f1236e212ee50b9"}, {file = "more_itertools-5.0.0-py3-none-any.whl", hash = "sha256:fe7a7cae1ccb57d33952113ff4fa1bc5f879963600ed74918f1236e212ee50b9"},
{file = "more-itertools-8.3.0.tar.gz", hash = "sha256:558bb897a2232f5e4f8e2399089e35aecb746e1f9191b6584a151647e89267be"},
{file = "more_itertools-8.3.0-py3-none-any.whl", hash = "sha256:7818f596b1e87be009031c7653d01acc46ed422e6656b394b0f765ce66ed4982"},
{file = "more-itertools-8.4.0.tar.gz", hash = "sha256:68c70cc7167bdf5c7c9d8f6954a7837089c6a36bf565383919bb595efb8a17e5"}, {file = "more-itertools-8.4.0.tar.gz", hash = "sha256:68c70cc7167bdf5c7c9d8f6954a7837089c6a36bf565383919bb595efb8a17e5"},
{file = "more_itertools-8.4.0-py3-none-any.whl", hash = "sha256:b78134b2063dd214000685165d81c154522c3ee0a1c0d4d113c80361c234c5a2"}, {file = "more_itertools-8.4.0-py3-none-any.whl", hash = "sha256:b78134b2063dd214000685165d81c154522c3ee0a1c0d4d113c80361c234c5a2"},
{file = "more-itertools-8.5.0.tar.gz", hash = "sha256:6f83822ae94818eae2612063a5101a7311e68ae8002005b5e05f03fd74a86a20"},
{file = "more_itertools-8.5.0-py3-none-any.whl", hash = "sha256:9b30f12df9393f0d28af9210ff8efe48d10c94f73e5daf886f10c4b0b0b4f03c"},
] ]
msgpack = [ msgpack = [
{file = "msgpack-1.0.0-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:cec8bf10981ed70998d98431cd814db0ecf3384e6b113366e7f36af71a0fca08"}, {file = "msgpack-1.0.0-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:cec8bf10981ed70998d98431cd814db0ecf3384e6b113366e7f36af71a0fca08"},
...@@ -1270,8 +1270,8 @@ pluggy = [ ...@@ -1270,8 +1270,8 @@ pluggy = [
{file = "pluggy-0.13.1.tar.gz", hash = "sha256:15b2acde666561e1298d71b523007ed7364de07029219b604cf808bfa1c765b0"}, {file = "pluggy-0.13.1.tar.gz", hash = "sha256:15b2acde666561e1298d71b523007ed7364de07029219b604cf808bfa1c765b0"},
] ]
poetry-core = [ poetry-core = [
{file = "poetry-core-1.0.0a9.tar.gz", hash = "sha256:f08e9829fd06609ca5615faa91739b589eb71e025a6aaf7ddffb698676eb7c8c"}, {file = "poetry-core-1.0.0b1.tar.gz", hash = "sha256:c7a64770780f6a4998eee1e260fc3b7e22fa1c9b94b05c0faa13aa512f95eaa1"},
{file = "poetry_core-1.0.0a9-py2.py3-none-any.whl", hash = "sha256:79a63629ae44533ba9aa828e0eff0002c61b3af5fc9bec212e006cc643f4eb19"}, {file = "poetry_core-1.0.0b1-py2.py3-none-any.whl", hash = "sha256:92d2a33c27c733e746425c6506fdf583909e3ce5de4591deb23a4efb13f1a72c"},
] ]
pre-commit = [ pre-commit = [
{file = "pre_commit-2.6.0-py2.py3-none-any.whl", hash = "sha256:e8b1315c585052e729ab7e99dcca5698266bedce9067d21dc909c23e3ceed626"}, {file = "pre_commit-2.6.0-py2.py3-none-any.whl", hash = "sha256:e8b1315c585052e729ab7e99dcca5698266bedce9067d21dc909c23e3ceed626"},
...@@ -1371,6 +1371,7 @@ six = [ ...@@ -1371,6 +1371,7 @@ six = [
] ]
subprocess32 = [ subprocess32 = [
{file = "subprocess32-3.5.4-cp27-cp27m-macosx_10_6_intel.whl", hash = "sha256:88e37c1aac5388df41cc8a8456bb49ebffd321a3ad4d70358e3518176de3a56b"}, {file = "subprocess32-3.5.4-cp27-cp27m-macosx_10_6_intel.whl", hash = "sha256:88e37c1aac5388df41cc8a8456bb49ebffd321a3ad4d70358e3518176de3a56b"},
{file = "subprocess32-3.5.4-cp27-cp27mu-manylinux2014_x86_64.whl", hash = "sha256:e45d985aef903c5b7444d34350b05da91a9e0ea015415ab45a21212786c649d0"},
{file = "subprocess32-3.5.4.tar.gz", hash = "sha256:eb2937c80497978d181efa1b839ec2d9622cf9600a039a79d0e108d1f9aec79d"}, {file = "subprocess32-3.5.4.tar.gz", hash = "sha256:eb2937c80497978d181efa1b839ec2d9622cf9600a039a79d0e108d1f9aec79d"},
] ]
termcolor = [ termcolor = [
......
...@@ -29,6 +29,7 @@ class DebugResolveCommand(InitCommand): ...@@ -29,6 +29,7 @@ class DebugResolveCommand(InitCommand):
def handle(self): def handle(self):
from poetry.core.packages.project_package import ProjectPackage from poetry.core.packages.project_package import ProjectPackage
from poetry.factory import Factory
from poetry.io.null_io import NullIO from poetry.io.null_io import NullIO
from poetry.puzzle import Solver from poetry.puzzle import Solver
from poetry.repositories.pool import Pool from poetry.repositories.pool import Pool
...@@ -59,7 +60,6 @@ class DebugResolveCommand(InitCommand): ...@@ -59,7 +60,6 @@ class DebugResolveCommand(InitCommand):
for constraint in requirements: for constraint in requirements:
name = constraint.pop("name") name = constraint.pop("name")
dep = package.add_dependency(name, constraint)
extras = [] extras = []
for extra in self.option("extras"): for extra in self.option("extras"):
if " " in extra: if " " in extra:
...@@ -67,8 +67,9 @@ class DebugResolveCommand(InitCommand): ...@@ -67,8 +67,9 @@ class DebugResolveCommand(InitCommand):
else: else:
extras.append(extra) extras.append(extra)
for ex in extras: constraint["extras"] = extras
dep.extras.append(ex)
package.add_dependency(Factory.create_dependency(name, constraint))
package.python_versions = self.option("python") or ( package.python_versions = self.option("python") or (
self.poetry.package.python_versions self.poetry.package.python_versions
...@@ -122,7 +123,7 @@ class DebugResolveCommand(InitCommand): ...@@ -122,7 +123,7 @@ class DebugResolveCommand(InitCommand):
pkg = op.package pkg = op.package
row = [ row = [
"<c1>{}</c1>".format(pkg.name), "<c1>{}</c1>".format(pkg.complete_name),
"<b>{}</b>".format(pkg.version), "<b>{}</b>".format(pkg.version),
"", "",
] ]
......
...@@ -388,7 +388,7 @@ The <c1>init</c1> command creates a basic <comment>pyproject.toml</> file in the ...@@ -388,7 +388,7 @@ The <c1>init</c1> command creates a basic <comment>pyproject.toml</> file in the
pair["extras"] = extras pair["extras"] = extras
package = Provider.get_package_from_vcs( package = Provider.get_package_from_vcs(
"git", url.url, reference=pair.get("rev") "git", url.url, rev=pair.get("rev")
) )
pair["name"] = package.name pair["name"] = package.name
result.append(pair) result.append(pair)
......
...@@ -37,6 +37,7 @@ lists all packages available.""" ...@@ -37,6 +37,7 @@ lists all packages available."""
from poetry.core.semver import Version from poetry.core.semver import Version
from poetry.repositories.installed_repository import InstalledRepository from poetry.repositories.installed_repository import InstalledRepository
from poetry.utils.helpers import get_package_version_display_string
package = self.argument("package") package = self.argument("package")
...@@ -144,12 +145,31 @@ lists all packages available.""" ...@@ -144,12 +145,31 @@ lists all packages available."""
if not self.option("outdated") or update_status != "up-to-date": if not self.option("outdated") or update_status != "up-to-date":
name_length = max(name_length, current_length) name_length = max(name_length, current_length)
version_length = max( version_length = max(
version_length, len(locked.full_pretty_version) version_length,
len(
get_package_version_display_string(
locked, root=self.poetry.file.parent
)
),
)
latest_length = max(
latest_length,
len(
get_package_version_display_string(
latest, root=self.poetry.file.parent
)
),
) )
latest_length = max(latest_length, len(latest.full_pretty_version))
else: else:
name_length = max(name_length, current_length) name_length = max(name_length, current_length)
version_length = max(version_length, len(locked.full_pretty_version)) version_length = max(
version_length,
len(
get_package_version_display_string(
locked, root=self.poetry.file.parent
)
),
)
write_version = name_length + version_length + 3 <= width write_version = name_length + version_length + 3 <= width
write_latest = name_length + version_length + latest_length + 3 <= width write_latest = name_length + version_length + latest_length + 3 <= width
...@@ -185,7 +205,10 @@ lists all packages available.""" ...@@ -185,7 +205,10 @@ lists all packages available."""
) )
if write_version: if write_version:
line += " <b>{:{}}</b>".format( line += " <b>{:{}}</b>".format(
locked.full_pretty_version, version_length get_package_version_display_string(
locked, root=self.poetry.file.parent
),
version_length,
) )
if show_latest: if show_latest:
latest = latest_packages[locked.pretty_name] latest = latest_packages[locked.pretty_name]
...@@ -199,7 +222,11 @@ lists all packages available.""" ...@@ -199,7 +222,11 @@ lists all packages available."""
color = "yellow" color = "yellow"
line += " <fg={}>{:{}}</>".format( line += " <fg={}>{:{}}</>".format(
color, latest.full_pretty_version, latest_length color,
get_package_version_display_string(
latest, root=self.poetry.file.parent
),
latest_length,
) )
if write_description: if write_description:
......
File mode changed from 100644 to 100755
...@@ -69,6 +69,9 @@ class PackageInfo: ...@@ -69,6 +69,9 @@ class PackageInfo:
self.requires_python = requires_python self.requires_python = requires_python
self.files = files or [] self.files = files or []
self._cache_version = cache_version self._cache_version = cache_version
self._source_type = None
self._source_url = None
self._source_reference = None
@property @property
def cache_version(self): # type: () -> Optional[str] def cache_version(self): # type: () -> Optional[str]
...@@ -136,7 +139,13 @@ class PackageInfo: ...@@ -136,7 +139,13 @@ class PackageInfo:
"Unable to retrieve the package version for {}".format(name) "Unable to retrieve the package version for {}".format(name)
) )
package = Package(name=name, version=self.version) package = Package(
name=name,
version=self.version,
source_type=self._source_type,
source_url=self._source_url,
source_reference=self._source_reference,
)
package.description = self.summary package.description = self.summary
package.root_dir = root_dir package.root_dir = root_dir
package.python_versions = self.requires_python or "*" package.python_versions = self.requires_python or "*"
...@@ -166,14 +175,9 @@ class PackageInfo: ...@@ -166,14 +175,9 @@ class PackageInfo:
# this is the first time we encounter this extra for this package # this is the first time we encounter this extra for this package
package.extras[extra] = [] package.extras[extra] = []
# Activate extra dependencies if specified
if extras and extra in extras:
dependency.activate()
package.extras[extra].append(dependency) package.extras[extra].append(dependency)
if not dependency.is_optional() or dependency.is_activated(): if dependency not in package.requires:
# we skip add only if the dependency is option and was not activated as part of an extra
package.requires.append(dependency) package.requires.append(dependency)
return package return package
...@@ -197,7 +201,7 @@ class PackageInfo: ...@@ -197,7 +201,7 @@ class PackageInfo:
with requires.open(encoding="utf-8") as f: with requires.open(encoding="utf-8") as f:
requirements = parse_requires(f.read()) requirements = parse_requires(f.read())
return cls( info = cls(
name=dist.name, name=dist.name,
version=dist.version, version=dist.version,
summary=dist.summary, summary=dist.summary,
...@@ -206,6 +210,11 @@ class PackageInfo: ...@@ -206,6 +210,11 @@ class PackageInfo:
requires_python=dist.requires_python, requires_python=dist.requires_python,
) )
info._source_type = "file"
info._source_url = Path(dist.filename).resolve().as_posix()
return info
@classmethod @classmethod
def _from_sdist_file(cls, path): # type: (Path) -> PackageInfo def _from_sdist_file(cls, path): # type: (Path) -> PackageInfo
""" """
...@@ -501,23 +510,26 @@ class PackageInfo: ...@@ -501,23 +510,26 @@ class PackageInfo:
""" """
project_package = cls._get_poetry_package(path) project_package = cls._get_poetry_package(path)
if project_package: if project_package:
return cls.from_package(project_package) info = cls.from_package(project_package)
else:
info = cls.from_metadata(path)
info = cls.from_metadata(path) if not info or info.requires_dist is None:
try:
if disable_build:
info = cls.from_setup_files(path)
else:
info = cls._pep517_metadata(path)
except PackageInfoError:
if not info:
raise
if info and info.requires_dist is not None: # we discovered PkgInfo but no requirements were listed
# return only if requirements are discovered
return info
try: info._source_type = "directory"
if disable_build: info._source_url = path.as_posix()
return cls.from_setup_files(path)
return cls._pep517_metadata(path) return info
except PackageInfoError as e:
if info:
# we discovered PkgInfo but no requirements were listed
return info
raise e
@classmethod @classmethod
def from_sdist(cls, path): # type: (Path) -> PackageInfo def from_sdist(cls, path): # type: (Path) -> PackageInfo
......
...@@ -556,7 +556,7 @@ class Executor(object): ...@@ -556,7 +556,7 @@ class Executor(object):
git.checkout(package.source_reference, src_dir) git.checkout(package.source_reference, src_dir)
# Now we just need to install from the source directory # Now we just need to install from the source directory
package.source_url = str(src_dir) package._source_url = str(src_dir)
return self._install_directory(operation) return self._install_directory(operation)
...@@ -599,7 +599,7 @@ class Executor(object): ...@@ -599,7 +599,7 @@ class Executor(object):
def _download_archive(self, operation, link): # type: (Operation, Link) -> Path def _download_archive(self, operation, link): # type: (Operation, Link) -> Path
response = self._authenticator.request( response = self._authenticator.request(
"get", link.url, stream=True, io=self._sections.get(id(operation)) "get", link.url, stream=True, io=self._sections.get(id(operation), self._io)
) )
wheel_size = response.headers.get("content-length") wheel_size = response.headers.get("content-length")
operation_message = self.get_operation_message(operation) operation_message = self.get_operation_message(operation)
......
...@@ -261,8 +261,8 @@ class PipInstaller(BaseInstaller): ...@@ -261,8 +261,8 @@ class PipInstaller(BaseInstaller):
# Now we just need to install from the source directory # Now we just need to install from the source directory
pkg = Package(package.name, package.version) pkg = Package(package.name, package.version)
pkg.source_type = "directory" pkg._source_type = "directory"
pkg.source_url = str(src_dir) pkg._source_url = str(src_dir)
pkg.develop = package.develop pkg.develop = package.develop
self.install_directory(pkg) self.install_directory(pkg)
...@@ -36,18 +36,18 @@ class Incompatibility: ...@@ -36,18 +36,18 @@ class Incompatibility:
# Short-circuit in the common case of a two-term incompatibility with # Short-circuit in the common case of a two-term incompatibility with
# two different packages (for example, a dependency). # two different packages (for example, a dependency).
or len(terms) == 2 or len(terms) == 2
and terms[0].dependency.name != terms[-1].dependency.name and terms[0].dependency.complete_name != terms[-1].dependency.complete_name
): ):
pass pass
else: else:
# Coalesce multiple terms about the same package if possible. # Coalesce multiple terms about the same package if possible.
by_name = {} # type: Dict[str, Dict[str, Term]] by_name = {} # type: Dict[str, Dict[str, Term]]
for term in terms: for term in terms:
if term.dependency.name not in by_name: if term.dependency.complete_name not in by_name:
by_name[term.dependency.name] = {} by_name[term.dependency.complete_name] = {}
by_ref = by_name[term.dependency.name] by_ref = by_name[term.dependency.complete_name]
ref = term.dependency.name ref = term.dependency.complete_name
if ref in by_ref: if ref in by_ref:
by_ref[ref] = by_ref[ref].intersect(term) by_ref[ref] = by_ref[ref].intersect(term)
...@@ -432,7 +432,7 @@ class Incompatibility: ...@@ -432,7 +432,7 @@ class Incompatibility:
def _terse(self, term, allow_every=False): def _terse(self, term, allow_every=False):
if allow_every and term.constraint.is_any(): if allow_every and term.constraint.is_any():
return "every version of {}".format(term.dependency.name) return "every version of {}".format(term.dependency.complete_name)
return str(term.dependency) return str(term.dependency)
......
...@@ -65,7 +65,7 @@ class PartialSolution: ...@@ -65,7 +65,7 @@ class PartialSolution:
return [ return [
term.dependency term.dependency
for term in self._positive.values() for term in self._positive.values()
if term.dependency.name not in self._decisions if term.dependency.complete_name not in self._decisions
] ]
def decide(self, package): # type: (Package) -> None def decide(self, package): # type: (Package) -> None
...@@ -81,7 +81,7 @@ class PartialSolution: ...@@ -81,7 +81,7 @@ class PartialSolution:
self._attempted_solutions += 1 self._attempted_solutions += 1
self._backtracking = False self._backtracking = False
self._decisions[package.name] = package self._decisions[package.complete_name] = package
self._assign( self._assign(
Assignment.decision(package, self.decision_level, len(self._assignments)) Assignment.decision(package, self.decision_level, len(self._assignments))
...@@ -120,9 +120,9 @@ class PartialSolution: ...@@ -120,9 +120,9 @@ class PartialSolution:
packages = set() packages = set()
while self._assignments[-1].decision_level > decision_level: while self._assignments[-1].decision_level > decision_level:
removed = self._assignments.pop(-1) removed = self._assignments.pop(-1)
packages.add(removed.dependency.name) packages.add(removed.dependency.complete_name)
if removed.is_decision(): if removed.is_decision():
del self._decisions[removed.dependency.name] del self._decisions[removed.dependency.complete_name]
# Re-compute _positive and _negative for the packages that were removed. # Re-compute _positive and _negative for the packages that were removed.
for package in packages: for package in packages:
...@@ -133,21 +133,21 @@ class PartialSolution: ...@@ -133,21 +133,21 @@ class PartialSolution:
del self._negative[package] del self._negative[package]
for assignment in self._assignments: for assignment in self._assignments:
if assignment.dependency.name in packages: if assignment.dependency.complete_name in packages:
self._register(assignment) self._register(assignment)
def _register(self, assignment): # type: (Assignment) -> None def _register(self, assignment): # type: (Assignment) -> None
""" """
Registers an Assignment in _positive or _negative. Registers an Assignment in _positive or _negative.
""" """
name = assignment.dependency.name name = assignment.dependency.complete_name
old_positive = self._positive.get(name) old_positive = self._positive.get(name)
if old_positive is not None: if old_positive is not None:
self._positive[name] = old_positive.intersect(assignment) self._positive[name] = old_positive.intersect(assignment)
return return
ref = assignment.dependency.name ref = assignment.dependency.complete_name
negative_by_ref = self._negative.get(name) negative_by_ref = self._negative.get(name)
old_negative = None if negative_by_ref is None else negative_by_ref.get(ref) old_negative = None if negative_by_ref is None else negative_by_ref.get(ref)
if old_negative is None: if old_negative is None:
...@@ -174,12 +174,12 @@ class PartialSolution: ...@@ -174,12 +174,12 @@ class PartialSolution:
assigned_term = None # type: Term assigned_term = None # type: Term
for assignment in self._assignments: for assignment in self._assignments:
if assignment.dependency.name != term.dependency.name: if assignment.dependency.complete_name != term.dependency.complete_name:
continue continue
if ( if (
not assignment.dependency.is_root not assignment.dependency.is_root
and not assignment.dependency.name == term.dependency.name and not assignment.dependency.is_same_package_as(term.dependency)
): ):
if not assignment.is_positive(): if not assignment.is_positive():
continue continue
...@@ -203,15 +203,15 @@ class PartialSolution: ...@@ -203,15 +203,15 @@ class PartialSolution:
return self.relation(term) == SetRelation.SUBSET return self.relation(term) == SetRelation.SUBSET
def relation(self, term): # type: (Term) -> int def relation(self, term): # type: (Term) -> int
positive = self._positive.get(term.dependency.name) positive = self._positive.get(term.dependency.complete_name)
if positive is not None: if positive is not None:
return positive.relation(term) return positive.relation(term)
by_ref = self._negative.get(term.dependency.name) by_ref = self._negative.get(term.dependency.complete_name)
if by_ref is None: if by_ref is None:
return SetRelation.OVERLAPPING return SetRelation.OVERLAPPING
negative = by_ref[term.dependency.name] negative = by_ref[term.dependency.complete_name]
if negative is None: if negative is None:
return SetRelation.OVERLAPPING return SetRelation.OVERLAPPING
......
...@@ -38,7 +38,7 @@ class Term(object): ...@@ -38,7 +38,7 @@ class Term(object):
Returns whether this term satisfies another. Returns whether this term satisfies another.
""" """
return ( return (
self.dependency.name == other.dependency.name self.dependency.complete_name == other.dependency.complete_name
and self.relation(other) == SetRelation.SUBSET and self.relation(other) == SetRelation.SUBSET
) )
...@@ -47,9 +47,9 @@ class Term(object): ...@@ -47,9 +47,9 @@ class Term(object):
Returns the relationship between the package versions Returns the relationship between the package versions
allowed by this term and another. allowed by this term and another.
""" """
if self.dependency.name != other.dependency.name: if self.dependency.complete_name != other.dependency.complete_name:
raise ValueError( raise ValueError(
"{} should refer to {}".format(other, self.dependency.name) "{} should refer to {}".format(other, self.dependency.complete_name)
) )
other_constraint = other.constraint other_constraint = other.constraint
...@@ -111,9 +111,9 @@ class Term(object): ...@@ -111,9 +111,9 @@ class Term(object):
Returns a Term that represents the packages Returns a Term that represents the packages
allowed by both this term and another allowed by both this term and another
""" """
if self.dependency.name != other.dependency.name: if self.dependency.complete_name != other.dependency.complete_name:
raise ValueError( raise ValueError(
"{} should refer to {}".format(other, self.dependency.name) "{} should refer to {}".format(other, self.dependency.complete_name)
) )
if self._compatible_dependency(other.dependency): if self._compatible_dependency(other.dependency):
...@@ -151,17 +151,14 @@ class Term(object): ...@@ -151,17 +151,14 @@ class Term(object):
return ( return (
self.dependency.is_root self.dependency.is_root
or other.is_root or other.is_root
or other.name == self.dependency.name or other.is_same_package_as(self.dependency)
) )
def _non_empty_term(self, constraint, is_positive): def _non_empty_term(self, constraint, is_positive):
if constraint.is_empty(): if constraint.is_empty():
return return
dep = Dependency(self.dependency.name, constraint) return Term(self.dependency.with_constraint(constraint), is_positive)
dep.python_versions = str(self.dependency.python_versions)
return Term(dep, is_positive)
def __str__(self): def __str__(self):
return "{}{}".format("not " if not self.is_positive() else "", self._dependency) return "{}{}".format("not " if not self.is_positive() else "", self._dependency)
......
...@@ -183,7 +183,7 @@ class VersionSolver: ...@@ -183,7 +183,7 @@ class VersionSolver:
unsatisfied.dependency, not unsatisfied.is_positive(), incompatibility unsatisfied.dependency, not unsatisfied.is_positive(), incompatibility
) )
return unsatisfied.dependency.name return unsatisfied.dependency.complete_name
def _resolve_conflict( def _resolve_conflict(
self, incompatibility self, incompatibility
...@@ -371,7 +371,7 @@ class VersionSolver: ...@@ -371,7 +371,7 @@ class VersionSolver:
self._add_incompatibility( self._add_incompatibility(
Incompatibility([Term(dependency, True)], PackageNotFoundCause(e)) Incompatibility([Term(dependency, True)], PackageNotFoundCause(e))
) )
return dependency.name return dependency.complete_name
try: try:
version = packages[0] version = packages[0]
...@@ -387,7 +387,7 @@ class VersionSolver: ...@@ -387,7 +387,7 @@ class VersionSolver:
Incompatibility([Term(dependency, True)], NoVersionsCause()) Incompatibility([Term(dependency, True)], NoVersionsCause())
) )
return dependency.name return dependency.complete_name
version = self._provider.complete_package(version) version = self._provider.complete_package(version)
...@@ -402,7 +402,7 @@ class VersionSolver: ...@@ -402,7 +402,7 @@ class VersionSolver:
# unit propagation which will guide us to choose a better version. # unit propagation which will guide us to choose a better version.
conflict = conflict or all( conflict = conflict or all(
[ [
term.dependency.name == dependency.name term.dependency.complete_name == dependency.complete_name
or self._solution.satisfies(term) or self._solution.satisfies(term)
for term in incompatibility.terms for term in incompatibility.terms
] ]
...@@ -411,10 +411,12 @@ class VersionSolver: ...@@ -411,10 +411,12 @@ class VersionSolver:
if not conflict: if not conflict:
self._solution.decide(version) self._solution.decide(version)
self._log( self._log(
"selecting {} ({})".format(version.name, version.full_pretty_version) "selecting {} ({})".format(
version.complete_name, version.full_pretty_version
)
) )
return dependency.name return dependency.complete_name
def _excludes_single_version(self, constraint): # type: (Any) -> bool def _excludes_single_version(self, constraint): # type: (Any) -> bool
return isinstance(VersionRange().difference(constraint), Version) return isinstance(VersionRange().difference(constraint), Version)
...@@ -435,31 +437,29 @@ class VersionSolver: ...@@ -435,31 +437,29 @@ class VersionSolver:
self._log("fact: {}".format(incompatibility)) self._log("fact: {}".format(incompatibility))
for term in incompatibility.terms: for term in incompatibility.terms:
if term.dependency.name not in self._incompatibilities: if term.dependency.complete_name not in self._incompatibilities:
self._incompatibilities[term.dependency.name] = [] self._incompatibilities[term.dependency.complete_name] = []
if incompatibility in self._incompatibilities[term.dependency.name]: if (
incompatibility
in self._incompatibilities[term.dependency.complete_name]
):
continue continue
self._incompatibilities[term.dependency.name].append(incompatibility) self._incompatibilities[term.dependency.complete_name].append(
incompatibility
)
def _get_locked(self, dependency): # type: (Dependency) -> Union[Package, None] def _get_locked(self, dependency): # type: (Dependency) -> Union[Package, None]
if dependency.name in self._use_latest: if dependency.complete_name in self._use_latest:
return return
locked = self._locked.get(dependency.name) locked = self._locked.get(dependency.complete_name)
if not locked: if not locked:
return return
if dependency.extras: if not dependency.is_same_package_as(locked):
locked.requires_extras = dependency.extras return
if not dependency.transitive_marker.without_extras().is_any():
marker_intersection = dependency.transitive_marker.without_extras().intersect(
locked.dependency.marker.without_extras()
)
if not marker_intersection.is_empty():
locked.dependency.transitive_marker = marker_intersection
return locked return locked
......
from typing import List
from poetry.core.packages.dependency import Dependency
from poetry.core.packages.package import Package
class DependencyPackage(object): class DependencyPackage(object):
def __init__(self, dependency, package): def __init__(self, dependency, package): # type: (Dependency, Package) -> None
self._dependency = dependency self._dependency = dependency
self._package = package self._package = package
@property @property
def dependency(self): def dependency(self): # type: () -> Dependency
return self._dependency return self._dependency
@property @property
def package(self): def package(self): # type: () -> Package
return self._package return self._package
def clone(self): # type: () -> DependencyPackage def clone(self): # type: () -> DependencyPackage
return self.__class__(self._dependency, self._package.clone()) return self.__class__(self._dependency, self._package.clone())
def with_features(self, features): # type: (List[str]) -> "DependencyPackage"
return self.__class__(self._dependency, self._package.with_features(features))
def without_features(self): # type: () -> "DependencyPackage"
return self.with_features([])
def __getattr__(self, name): def __getattr__(self, name):
return getattr(self._package, name) return getattr(self._package, name)
......
import json import json
import logging import logging
import os
import re import re
from hashlib import sha256 from hashlib import sha256
from typing import List from typing import List
from tomlkit import array
from tomlkit import document from tomlkit import document
from tomlkit import inline_table from tomlkit import inline_table
from tomlkit import item from tomlkit import item
...@@ -18,6 +20,7 @@ from poetry.core.packages.package import Package ...@@ -18,6 +20,7 @@ from poetry.core.packages.package import Package
from poetry.core.semver import parse_constraint from poetry.core.semver import parse_constraint
from poetry.core.semver.version import Version from poetry.core.semver.version import Version
from poetry.core.version.markers import parse_marker from poetry.core.version.markers import parse_marker
from poetry.utils._compat import OrderedDict
from poetry.utils._compat import Path from poetry.utils._compat import Path
from poetry.utils.toml_file import TomlFile from poetry.utils.toml_file import TomlFile
...@@ -75,6 +78,8 @@ class Locker(object): ...@@ -75,6 +78,8 @@ class Locker(object):
""" """
Searches and returns a repository of locked packages. Searches and returns a repository of locked packages.
""" """
from poetry.factory import Factory
if not self.is_locked(): if not self.is_locked():
return poetry.repositories.Repository() return poetry.repositories.Repository()
...@@ -92,7 +97,21 @@ class Locker(object): ...@@ -92,7 +97,21 @@ class Locker(object):
return packages return packages
for info in locked_packages: for info in locked_packages:
package = Package(info["name"], info["version"], info["version"]) source = info.get("source", {})
source_type = source.get("type")
url = source.get("url")
if source_type in ["directory", "file"]:
url = self._lock.path.parent.joinpath(url).resolve().as_posix()
package = Package(
info["name"],
info["version"],
info["version"],
source_type=source_type,
source_url=url,
source_reference=source.get("reference"),
source_resolved_reference=source.get("resolved_reference"),
)
package.description = info.get("description", "") package.description = info.get("description", "")
package.category = info["category"] package.category = info["category"]
package.optional = info["optional"] package.optional = info["optional"]
...@@ -137,20 +156,23 @@ class Locker(object): ...@@ -137,20 +156,23 @@ class Locker(object):
for dep_name, constraint in info.get("dependencies", {}).items(): for dep_name, constraint in info.get("dependencies", {}).items():
if isinstance(constraint, list): if isinstance(constraint, list):
for c in constraint: for c in constraint:
package.add_dependency(dep_name, c) package.add_dependency(
Factory.create_dependency(
dep_name, c, root_dir=self._lock.path.parent
)
)
continue continue
package.add_dependency(dep_name, constraint) package.add_dependency(
Factory.create_dependency(
dep_name, constraint, root_dir=self._lock.path.parent
)
)
if "develop" in info: if "develop" in info:
package.develop = info["develop"] package.develop = info["develop"]
if "source" in info:
package.source_type = info["source"].get("type", "")
package.source_url = info["source"]["url"]
package.source_reference = info["source"]["reference"]
packages.add_package(package) packages.add_package(package)
return packages return packages
...@@ -181,15 +203,17 @@ class Locker(object): ...@@ -181,15 +203,17 @@ class Locker(object):
if root.extras: if root.extras:
lock["extras"] = { lock["extras"] = {
extra: [dep.pretty_name for dep in deps] extra: [dep.pretty_name for dep in deps]
for extra, deps in root.extras.items() for extra, deps in sorted(root.extras.items())
} }
lock["metadata"] = { lock["metadata"] = OrderedDict(
"lock-version": self._VERSION, [
"python-versions": root.python_versions, ("lock-version", self._VERSION),
"content-hash": self._content_hash, ("python-versions", root.python_versions),
"files": files, ("content-hash", self._content_hash),
} ("files", files),
]
)
if not self.is_locked() or lock != self.lock_data: if not self.is_locked() or lock != self.lock_data:
self._write_lock_data(lock) self._write_lock_data(lock)
...@@ -270,9 +294,6 @@ class Locker(object): ...@@ -270,9 +294,6 @@ class Locker(object):
def _dump_package(self, package): # type: (Package) -> dict def _dump_package(self, package): # type: (Package) -> dict
dependencies = {} dependencies = {}
for dependency in sorted(package.requires, key=lambda d: d.name): for dependency in sorted(package.requires, key=lambda d: d.name):
if dependency.is_optional() and not dependency.is_activated():
continue
if dependency.pretty_name not in dependencies: if dependency.pretty_name not in dependencies:
dependencies[dependency.pretty_name] = [] dependencies[dependency.pretty_name] = []
...@@ -298,15 +319,27 @@ class Locker(object): ...@@ -298,15 +319,27 @@ class Locker(object):
constraint["version"] for constraint in constraints constraint["version"] for constraint in constraints
] ]
data = { data = OrderedDict(
"name": package.pretty_name, [
"version": package.pretty_version, ("name", package.pretty_name),
"description": package.description or "", ("version", package.pretty_version),
"category": package.category, ("description", package.description or ""),
"optional": package.optional, ("category", package.category),
"python-versions": package.python_versions, ("optional", package.optional),
"files": sorted(package.files, key=lambda x: x["file"]), ("python-versions", package.python_versions),
} ("files", sorted(package.files, key=lambda x: x["file"])),
]
)
if dependencies:
data["dependencies"] = table()
for k, constraints in dependencies.items():
if len(constraints) == 1:
data["dependencies"][k] = constraints[0]
else:
data["dependencies"][k] = array().multiline(True)
for constraint in constraints:
data["dependencies"][k].append(constraint)
if package.extras: if package.extras:
extras = {} extras = {}
...@@ -318,20 +351,29 @@ class Locker(object): ...@@ -318,20 +351,29 @@ class Locker(object):
data["extras"] = extras data["extras"] = extras
if dependencies: if package.source_url:
for k, constraints in dependencies.items(): url = package.source_url
if len(constraints) == 1: if package.source_type in ["file", "directory"]:
dependencies[k] = constraints[0] # The lock file should only store paths relative to the root project
url = Path(
os.path.relpath(
Path(url).as_posix(), self._lock.path.parent.as_posix()
)
).as_posix()
data["dependencies"] = dependencies data["source"] = OrderedDict()
if package.source_url:
data["source"] = {
"url": package.source_url,
"reference": package.source_reference,
}
if package.source_type: if package.source_type:
data["source"]["type"] = package.source_type data["source"]["type"] = package.source_type
data["source"]["url"] = url
if package.source_reference:
data["source"]["reference"] = package.source_reference
if package.source_resolved_reference:
data["source"]["resolved_reference"] = package.source_resolved_reference
if package.source_type == "directory": if package.source_type == "directory":
data["develop"] = package.develop data["develop"] = package.develop
......
...@@ -14,7 +14,9 @@ class PackageCollection(list): ...@@ -14,7 +14,9 @@ class PackageCollection(list):
self.append(package) self.append(package)
def append(self, package): def append(self, package):
if not isinstance(package, DependencyPackage): if isinstance(package, DependencyPackage):
package = DependencyPackage(self._dependency, package) package = package.package
package = DependencyPackage(self._dependency, package)
return super(PackageCollection, self).append(package) return super(PackageCollection, self).append(package)
...@@ -103,7 +103,7 @@ class Provider: ...@@ -103,7 +103,7 @@ class Provider:
for constraint in self._search_for.keys(): for constraint in self._search_for.keys():
if ( if (
constraint.name == dependency.name constraint.is_same_package_as(dependency)
and constraint.constraint.intersect(dependency.constraint) and constraint.constraint.intersect(dependency.constraint)
== dependency.constraint == dependency.constraint
): ):
...@@ -132,15 +132,7 @@ class Provider: ...@@ -132,15 +132,7 @@ class Provider:
elif dependency.is_url(): elif dependency.is_url():
packages = self.search_for_url(dependency) packages = self.search_for_url(dependency)
else: else:
constraint = dependency.constraint packages = self._pool.find_packages(dependency)
packages = self._pool.find_packages(
dependency.name,
constraint,
extras=dependency.extras,
allow_prereleases=dependency.allows_prereleases(),
repository=dependency.source_name,
)
packages.sort( packages.sort(
key=lambda p: ( key=lambda p: (
...@@ -167,17 +159,12 @@ class Provider: ...@@ -167,17 +159,12 @@ class Provider:
package = self.get_package_from_vcs( package = self.get_package_from_vcs(
dependency.vcs, dependency.vcs,
dependency.source, dependency.source,
dependency.reference, branch=dependency.branch,
tag=dependency.tag,
rev=dependency.rev,
name=dependency.name, name=dependency.name,
) )
for extra in dependency.extras:
if extra in package.extras:
for dep in package.extras[extra]:
dep.activate()
package.requires += package.extras[extra]
dependency._constraint = package.version dependency._constraint = package.version
dependency._pretty_constraint = package.version.text dependency._pretty_constraint = package.version.text
...@@ -187,7 +174,7 @@ class Provider: ...@@ -187,7 +174,7 @@ class Provider:
@classmethod @classmethod
def get_package_from_vcs( def get_package_from_vcs(
cls, vcs, url, reference=None, name=None cls, vcs, url, branch=None, tag=None, rev=None, name=None
): # type: (str, str, Optional[str], Optional[str]) -> Package ): # type: (str, str, Optional[str], Optional[str]) -> Package
if vcs != "git": if vcs != "git":
raise ValueError("Unsupported VCS dependency {}".format(vcs)) raise ValueError("Unsupported VCS dependency {}".format(vcs))
...@@ -199,6 +186,7 @@ class Provider: ...@@ -199,6 +186,7 @@ class Provider:
try: try:
git = Git() git = Git()
git.clone(url, tmp_dir) git.clone(url, tmp_dir)
reference = branch or tag or rev
if reference is not None: if reference is not None:
git.checkout(reference, tmp_dir) git.checkout(reference, tmp_dir)
else: else:
...@@ -207,10 +195,10 @@ class Provider: ...@@ -207,10 +195,10 @@ class Provider:
revision = git.rev_parse(reference, tmp_dir).strip() revision = git.rev_parse(reference, tmp_dir).strip()
package = cls.get_package_from_directory(tmp_dir, name=name) package = cls.get_package_from_directory(tmp_dir, name=name)
package._source_type = "git"
package.source_type = "git" package._source_url = url
package.source_url = url package._source_reference = reference
package.source_reference = revision package._source_resolved_reference = revision
except Exception: except Exception:
raise raise
finally: finally:
...@@ -242,18 +230,10 @@ class Provider: ...@@ -242,18 +230,10 @@ class Provider:
if dependency.base is not None: if dependency.base is not None:
package.root_dir = dependency.base package.root_dir = dependency.base
package.source_url = dependency.path.as_posix()
package.files = [ package.files = [
{"file": dependency.path.name, "hash": "sha256:" + dependency.hash()} {"file": dependency.path.name, "hash": "sha256:" + dependency.hash()}
] ]
for extra in dependency.extras:
if extra in package.extras:
for dep in package.extras[extra]:
dep.activate()
package.requires += package.extras[extra]
return [package] return [package]
@classmethod @classmethod
...@@ -267,9 +247,6 @@ class Provider: ...@@ -267,9 +247,6 @@ class Provider:
"Unable to determine package info from path: {}".format(file_path) "Unable to determine package info from path: {}".format(file_path)
) )
package.source_type = "file"
package.source_url = file_path.as_posix()
return package return package
def search_for_directory( def search_for_directory(
...@@ -289,19 +266,11 @@ class Provider: ...@@ -289,19 +266,11 @@ class Provider:
self._deferred_cache[dependency] = (dependency, package) self._deferred_cache[dependency] = (dependency, package)
package.source_url = dependency.path.as_posix()
package.develop = dependency.develop package.develop = dependency.develop
if dependency.base is not None: if dependency.base is not None:
package.root_dir = dependency.base package.root_dir = dependency.base
for extra in dependency.extras:
if extra in package.extras:
for dep in package.extras[extra]:
dep.activate()
package.requires += package.extras[extra]
return [package] return [package]
@classmethod @classmethod
...@@ -320,9 +289,6 @@ class Provider: ...@@ -320,9 +289,6 @@ class Provider:
) )
) )
package.source_type = "directory"
package.source_url = directory.as_posix()
return package return package
def search_for_url(self, dependency): # type: (URLDependency) -> List[Package] def search_for_url(self, dependency): # type: (URLDependency) -> List[Package]
...@@ -362,8 +328,8 @@ class Provider: ...@@ -362,8 +328,8 @@ class Provider:
package = cls.get_package_from_file(temp_dir / file_name) package = cls.get_package_from_file(temp_dir / file_name)
package.source_type = "url" package._source_type = "url"
package.source_url = url package._source_url = url
return package return package
...@@ -447,6 +413,7 @@ class Provider: ...@@ -447,6 +413,7 @@ class Provider:
def complete_package( def complete_package(
self, package self, package
): # type: (DependencyPackage) -> DependencyPackage ): # type: (DependencyPackage) -> DependencyPackage
if package.is_root(): if package.is_root():
package = package.clone() package = package.clone()
requires = package.all_requires requires = package.all_requires
...@@ -461,7 +428,7 @@ class Provider: ...@@ -461,7 +428,7 @@ class Provider:
self._pool.package( self._pool.package(
package.name, package.name,
package.version.text, package.version.text,
extras=package.requires_extras, extras=package.dependency.extras,
repository=package.dependency.source_name, repository=package.dependency.source_name,
), ),
) )
...@@ -480,13 +447,44 @@ class Provider: ...@@ -480,13 +447,44 @@ class Provider:
elif r.is_url(): elif r.is_url():
self.search_for_url(r) self.search_for_url(r)
_dependencies = [ optional_dependencies = []
r activated_extras = []
for r in requires for extra in package.dependency.extras:
if self._python_constraint.allows_any(r.python_constraint) if extra not in package.extras:
and r.name not in self.UNSAFE_PACKAGES continue
and (not self._env or r.marker.validate(self._env.marker_env))
] activated_extras.append(extra)
optional_dependencies += [d.name for d in package.extras[extra]]
_dependencies = []
# If some extras/features were required, we need to
# add a special dependency representing the base package
# to the current package
if package.dependency.extras:
if activated_extras:
package = package.with_features(activated_extras)
_dependencies.append(package.without_features().to_dependency())
for dep in requires:
if not self._python_constraint.allows_any(dep.python_constraint):
continue
if dep.name in self.UNSAFE_PACKAGES:
continue
if self._env and not dep.marker.validate(self._env.marker_env):
continue
if (
dep.is_optional()
and dep.name not in optional_dependencies
and not package.is_root()
):
continue
_dependencies.append(dep)
overrides = self._overrides.get(package, {}) overrides = self._overrides.get(package, {})
dependencies = [] dependencies = []
...@@ -683,18 +681,6 @@ class Provider: ...@@ -683,18 +681,6 @@ class Provider:
continue continue
dep.transitive_python_versions = str(python_constraint_intersection) dep.transitive_python_versions = str(python_constraint_intersection)
if (package.dependency.is_directory() or package.dependency.is_file()) and (
dep.is_directory() or dep.is_file()
):
relative_path = Path(
os.path.relpath(
dep.full_path.as_posix(), package.root_dir.as_posix()
)
)
# TODO: Improve the way we set the correct relative path for dependencies
dep._path = relative_path
clean_dependencies.append(dep) clean_dependencies.append(dep)
package.requires = clean_dependencies package.requires = clean_dependencies
......
...@@ -34,7 +34,7 @@ class Solver: ...@@ -34,7 +34,7 @@ class Solver:
installed, # type: Repository installed, # type: Repository
locked, # type: Repository locked, # type: Repository
io, # type: ConsoleIO io, # type: ConsoleIO
remove_untracked=False, # type: bool, remove_untracked=False, # type: bool
provider=None, # type: Optional[Provider] provider=None, # type: Optional[Provider]
): ):
self._package = package self._package = package
...@@ -100,18 +100,37 @@ class Solver: ...@@ -100,18 +100,37 @@ class Solver:
and locked.source_type == pkg.source_type and locked.source_type == pkg.source_type
and locked_source_url == pkg_source_url and locked_source_url == pkg_source_url
and locked.source_reference == pkg.source_reference and locked.source_reference == pkg.source_reference
and locked.source_resolved_reference
== pkg.source_resolved_reference
): ):
pkg = Package(pkg.name, locked.version) pkg = Package(
pkg.source_type = "git" pkg.name,
pkg.source_url = locked.source_url locked.version,
pkg.source_reference = locked.source_reference source_type="git",
source_url=locked.source_url,
source_reference=locked.source_reference,
source_resolved_reference=locked.source_resolved_reference,
)
break break
if pkg_source_url != package_source_url or ( if pkg_source_url != package_source_url or (
pkg.source_reference != package.source_reference (
not pkg.source_resolved_reference
or not package.source_resolved_reference
)
and pkg.source_reference != package.source_reference
and not pkg.source_reference.startswith( and not pkg.source_reference.startswith(
package.source_reference package.source_reference
) )
or (
pkg.source_resolved_reference
and package.source_resolved_reference
and pkg.source_resolved_reference
!= package.source_resolved_reference
and not pkg.source_resolved_reference.startswith(
package.source_resolved_reference
)
)
): ):
operations.append(Update(pkg, package, priority=depths[i])) operations.append(Update(pkg, package, priority=depths[i]))
else: else:
...@@ -226,17 +245,39 @@ class Solver: ...@@ -226,17 +245,39 @@ class Solver:
PackageNode(self._package, packages), aggregate_package_nodes PackageNode(self._package, packages), aggregate_package_nodes
) )
) )
# Return the packages in their original order with associated depths
final_packages = packages
depths = [results[package] for package in packages]
# Merging feature packages with base packages
final_packages = []
depths = []
for package in packages:
if package.features:
for _package in packages:
if (
_package.name == package.name
and not _package.is_same_package_as(package)
and _package.version == package.version
):
for dep in package.requires:
if dep.is_same_package_as(_package):
continue
if dep not in _package.requires:
_package.requires.append(dep)
continue
final_packages.append(package)
depths.append(results[package])
# Return the packages in their original order with associated depths
return final_packages, depths return final_packages, depths
class DFSNode(object): class DFSNode(object):
def __init__(self, id, name): def __init__(self, id, name, base_name):
self.id = id self.id = id
self.name = name self.name = name
self.base_name = base_name
def reachable(self): def reachable(self):
return [] return []
...@@ -302,13 +343,7 @@ def dfs_visit(node, back_edges, visited, sorted_nodes): ...@@ -302,13 +343,7 @@ def dfs_visit(node, back_edges, visited, sorted_nodes):
class PackageNode(DFSNode): class PackageNode(DFSNode):
def __init__( def __init__(
self, self, package, packages, previous=None, previous_dep=None, dep=None,
package,
packages,
previous=None,
previous_dep=None,
dep=None,
is_activated=True,
): ):
self.package = package self.package = package
self.packages = packages self.packages = packages
...@@ -323,11 +358,12 @@ class PackageNode(DFSNode): ...@@ -323,11 +358,12 @@ class PackageNode(DFSNode):
self.optional = True self.optional = True
else: else:
self.category = dep.category self.category = dep.category
self.optional = dep.is_optional() and not dep.is_activated() self.optional = dep.is_optional()
if not is_activated:
self.optional = True
super(PackageNode, self).__init__( super(PackageNode, self).__init__(
(package.name, self.category, self.optional), package.name (package.complete_name, self.category, self.optional),
package.complete_name,
package.name,
) )
def reachable(self): def reachable(self):
...@@ -341,29 +377,7 @@ class PackageNode(DFSNode): ...@@ -341,29 +377,7 @@ class PackageNode(DFSNode):
return [] return []
for dependency in self.package.all_requires: for dependency in self.package.all_requires:
is_activated = True if self.previous and self.previous.name == dependency.name:
if dependency.is_optional():
if not self.package.is_root() and (
not self.previous_dep or not self.previous_dep.extras
):
continue
is_activated = False
for group, extra_deps in self.package.extras.items():
if self.dep:
extras = self.previous_dep.extras
elif self.package.is_root():
extras = self.package.extras
else:
extras = []
if group in extras and dependency.name in (
d.name for d in self.package.extras[group]
):
is_activated = True
break
if self.previous and self.previous.package.name == dependency.name:
# We have a circular dependency. # We have a circular dependency.
# Since the dependencies are resolved we can # Since the dependencies are resolved we can
# simply skip it because we already have it # simply skip it because we already have it
...@@ -372,8 +386,9 @@ class PackageNode(DFSNode): ...@@ -372,8 +386,9 @@ class PackageNode(DFSNode):
continue continue
for pkg in self.packages: for pkg in self.packages:
if pkg.name == dependency.name and dependency.constraint.allows( if (
pkg.version pkg.complete_name == dependency.complete_name
and dependency.constraint.allows(pkg.version)
): ):
# If there is already a child with this name # If there is already a child with this name
# we merge the requirements # we merge the requirements
...@@ -383,6 +398,7 @@ class PackageNode(DFSNode): ...@@ -383,6 +398,7 @@ class PackageNode(DFSNode):
for child in children for child in children
): ):
continue continue
children.append( children.append(
PackageNode( PackageNode(
pkg, pkg,
...@@ -390,15 +406,21 @@ class PackageNode(DFSNode): ...@@ -390,15 +406,21 @@ class PackageNode(DFSNode):
self, self,
dependency, dependency,
self.dep or dependency, self.dep or dependency,
is_activated=is_activated,
) )
) )
return children return children
def visit(self, parents): def visit(self, parents):
# The root package, which has no parents, is defined as having depth -1 # The root package, which has no parents, is defined as having depth -1
# So that the root package's top-level dependencies have depth 0. # So that the root package's top-level dependencies have depth 0.
self.depth = 1 + max([parent.depth for parent in parents] + [-2]) self.depth = 1 + max(
[
parent.depth if parent.base_name != self.base_name else parent.depth - 1
for parent in parents
]
+ [-2]
)
def aggregate_package_nodes(nodes, children): def aggregate_package_nodes(nodes, children):
......
...@@ -12,9 +12,7 @@ class BaseRepository(object): ...@@ -12,9 +12,7 @@ class BaseRepository(object):
def package(self, name, version, extras=None): def package(self, name, version, extras=None):
raise NotImplementedError() raise NotImplementedError()
def find_packages( def find_packages(self, dependency):
self, name, constraint=None, extras=None, allow_prereleases=False
):
raise NotImplementedError() raise NotImplementedError()
def search(self, query): def search(self, query):
......
...@@ -76,9 +76,9 @@ class InstalledRepository(Repository): ...@@ -76,9 +76,9 @@ class InstalledRepository(Repository):
revision = git.rev_parse("HEAD", src).strip() revision = git.rev_parse("HEAD", src).strip()
url = git.remote_url(src) url = git.remote_url(src)
package.source_type = "git" package._source_type = "git"
package.source_url = url package._source_url = url
package.source_reference = revision package._source_reference = revision
@classmethod @classmethod
def set_package_vcs_properties(cls, package, env): # type: (Package, Env) -> None def set_package_vcs_properties(cls, package, env): # type: (Package, Env) -> None
...@@ -144,15 +144,15 @@ class InstalledRepository(Repository): ...@@ -144,15 +144,15 @@ class InstalledRepository(Repository):
break break
else: else:
# TODO: handle multiple source directories? # TODO: handle multiple source directories?
package.source_type = "directory" package._source_type = "directory"
package.source_url = paths.pop().as_posix() package._source_url = paths.pop().as_posix()
continue continue
if cls.is_vcs_package(path, env): if cls.is_vcs_package(path, env):
cls.set_package_vcs_properties(package, env) cls.set_package_vcs_properties(package, env)
else: else:
# If not, it's a path dependency # If not, it's a path dependency
package.source_type = "directory" package._source_type = "directory"
package.source_url = str(path.parent) package._source_url = str(path.parent)
return repo return repo
...@@ -222,17 +222,17 @@ class LegacyRepository(PyPiRepository): ...@@ -222,17 +222,17 @@ class LegacyRepository(PyPiRepository):
path=parsed.path, path=parsed.path,
) )
def find_packages( def find_packages(self, dependency):
self, name, constraint=None, extras=None, allow_prereleases=False
):
packages = [] packages = []
constraint = dependency.constraint
if constraint is None: if constraint is None:
constraint = "*" constraint = "*"
if not isinstance(constraint, VersionConstraint): if not isinstance(constraint, VersionConstraint):
constraint = parse_constraint(constraint) constraint = parse_constraint(constraint)
allow_prereleases = dependency.allows_prereleases()
if isinstance(constraint, VersionRange): if isinstance(constraint, VersionRange):
if ( if (
constraint.max is not None constraint.max is not None
...@@ -242,7 +242,7 @@ class LegacyRepository(PyPiRepository): ...@@ -242,7 +242,7 @@ class LegacyRepository(PyPiRepository):
): ):
allow_prereleases = True allow_prereleases = True
key = name key = dependency.name
if not constraint.is_any(): if not constraint.is_any():
key = "{}:{}".format(key, str(constraint)) key = "{}:{}".format(key, str(constraint))
...@@ -251,7 +251,7 @@ class LegacyRepository(PyPiRepository): ...@@ -251,7 +251,7 @@ class LegacyRepository(PyPiRepository):
if self._cache.store("matches").has(key): if self._cache.store("matches").has(key):
versions = self._cache.store("matches").get(key) versions = self._cache.store("matches").get(key)
else: else:
page = self._get("/{}/".format(canonicalize_name(name).replace(".", "-"))) page = self._get("/{}/".format(dependency.name.replace(".", "-")))
if page is None: if page is None:
return [] return []
...@@ -270,19 +270,19 @@ class LegacyRepository(PyPiRepository): ...@@ -270,19 +270,19 @@ class LegacyRepository(PyPiRepository):
for package_versions in (versions, ignored_pre_release_versions): for package_versions in (versions, ignored_pre_release_versions):
for version in package_versions: for version in package_versions:
package = Package(name, version) package = Package(
package.source_type = "legacy" dependency.name,
package.source_reference = self.name version,
package.source_url = self._url source_type="legacy",
source_reference=self.name,
if extras is not None: source_url=self._url,
package.requires_extras = extras )
packages.append(package) packages.append(package)
self._log( self._log(
"{} packages found for {} {}".format( "{} packages found for {} {}".format(
len(packages), name, str(constraint) len(packages), dependency.name, str(constraint)
), ),
level="debug", level="debug",
) )
...@@ -302,7 +302,7 @@ class LegacyRepository(PyPiRepository): ...@@ -302,7 +302,7 @@ class LegacyRepository(PyPiRepository):
We also need to download every file matching this release We also need to download every file matching this release
to get the various hashes. to get the various hashes.
Note that, this will be cached so the subsequent operations Note that this will be cached so the subsequent operations
should be much faster. should be much faster.
""" """
try: try:
...@@ -311,9 +311,9 @@ class LegacyRepository(PyPiRepository): ...@@ -311,9 +311,9 @@ class LegacyRepository(PyPiRepository):
return self._packages[index] return self._packages[index]
except ValueError: except ValueError:
package = super(LegacyRepository, self).package(name, version, extras) package = super(LegacyRepository, self).package(name, version, extras)
package.source_type = "legacy" package._source_type = "legacy"
package.source_url = self._url package._source_url = self._url
package.source_reference = self.name package._source_reference = self.name
return package return package
......
...@@ -144,13 +144,9 @@ class Pool(BaseRepository): ...@@ -144,13 +144,9 @@ class Pool(BaseRepository):
raise PackageNotFound("Package {} ({}) not found.".format(name, version)) raise PackageNotFound("Package {} ({}) not found.".format(name, version))
def find_packages( def find_packages(
self, self, dependency,
name,
constraint=None,
extras=None,
allow_prereleases=False,
repository=None,
): ):
repository = dependency.source_name
if repository is not None: if repository is not None:
repository = repository.lower() repository = repository.lower()
...@@ -162,15 +158,11 @@ class Pool(BaseRepository): ...@@ -162,15 +158,11 @@ class Pool(BaseRepository):
raise ValueError('Repository "{}" does not exist.'.format(repository)) raise ValueError('Repository "{}" does not exist.'.format(repository))
if repository is not None and not self._ignore_repository_names: if repository is not None and not self._ignore_repository_names:
return self.repository(repository).find_packages( return self.repository(repository).find_packages(dependency)
name, constraint, extras=extras, allow_prereleases=allow_prereleases
)
packages = [] packages = []
for idx, repo in enumerate(self._repositories): for repo in self._repositories:
packages += repo.find_packages( packages += repo.find_packages(dependency)
name, constraint, extras=extras, allow_prereleases=allow_prereleases
)
return packages return packages
......
...@@ -14,6 +14,7 @@ from cachecontrol.controller import logger as cache_control_logger ...@@ -14,6 +14,7 @@ from cachecontrol.controller import logger as cache_control_logger
from cachy import CacheManager from cachy import CacheManager
from html5lib.html5parser import parse from html5lib.html5parser import parse
from poetry.core.packages import Dependency
from poetry.core.packages import Package from poetry.core.packages import Package
from poetry.core.packages import dependency_from_pep_508 from poetry.core.packages import dependency_from_pep_508
from poetry.core.packages.utils.link import Link from poetry.core.packages.utils.link import Link
...@@ -79,22 +80,18 @@ class PyPiRepository(RemoteRepository): ...@@ -79,22 +80,18 @@ class PyPiRepository(RemoteRepository):
def session(self): def session(self):
return self._session return self._session
def find_packages( def find_packages(self, dependency): # type: (Dependency) -> List[Package]
self,
name, # type: str
constraint=None, # type: Union[VersionConstraint, str, None]
extras=None, # type: Union[list, None]
allow_prereleases=False, # type: bool
): # type: (...) -> List[Package]
""" """
Find packages on the remote server. Find packages on the remote server.
""" """
constraint = dependency.constraint
if constraint is None: if constraint is None:
constraint = "*" constraint = "*"
if not isinstance(constraint, VersionConstraint): if not isinstance(constraint, VersionConstraint):
constraint = parse_constraint(constraint) constraint = parse_constraint(constraint)
allow_prereleases = dependency.allows_prereleases()
if isinstance(constraint, VersionRange): if isinstance(constraint, VersionRange):
if ( if (
constraint.max is not None constraint.max is not None
...@@ -105,10 +102,10 @@ class PyPiRepository(RemoteRepository): ...@@ -105,10 +102,10 @@ class PyPiRepository(RemoteRepository):
allow_prereleases = True allow_prereleases = True
try: try:
info = self.get_package_info(name) info = self.get_package_info(dependency.name)
except PackageNotFound: except PackageNotFound:
self._log( self._log(
"No packages found for {} {}".format(name, str(constraint)), "No packages found for {} {}".format(dependency.name, str(constraint)),
level="debug", level="debug",
) )
return [] return []
...@@ -121,7 +118,7 @@ class PyPiRepository(RemoteRepository): ...@@ -121,7 +118,7 @@ class PyPiRepository(RemoteRepository):
# Bad release # Bad release
self._log( self._log(
"No release information found for {}-{}, skipping".format( "No release information found for {}-{}, skipping".format(
name, version dependency.name, version
), ),
level="debug", level="debug",
) )
...@@ -132,7 +129,7 @@ class PyPiRepository(RemoteRepository): ...@@ -132,7 +129,7 @@ class PyPiRepository(RemoteRepository):
except ParseVersionError: except ParseVersionError:
self._log( self._log(
'Unable to parse version "{}" for the {} package, skipping'.format( 'Unable to parse version "{}" for the {} package, skipping'.format(
version, name version, dependency.name
), ),
level="debug", level="debug",
) )
...@@ -145,13 +142,12 @@ class PyPiRepository(RemoteRepository): ...@@ -145,13 +142,12 @@ class PyPiRepository(RemoteRepository):
continue continue
if not constraint or (constraint and constraint.allows(package.version)): if not constraint or (constraint and constraint.allows(package.version)):
if extras is not None:
package.requires_extras = extras
packages.append(package) packages.append(package)
self._log( self._log(
"{} packages found for {} {}".format(len(packages), name, str(constraint)), "{} packages found for {} {}".format(
len(packages), dependency.name, str(constraint)
),
level="debug", level="debug",
) )
......
...@@ -29,32 +29,22 @@ class Repository(BaseRepository): ...@@ -29,32 +29,22 @@ class Repository(BaseRepository):
for package in self.packages: for package in self.packages:
if name == package.name and package.version.text == version: if name == package.name and package.version.text == version:
# Activate extra dependencies package = package.with_features(extras)
for extra in extras:
if extra in package.extras: return package
for extra_dep in package.extras[extra]:
for dep in package.requires: def find_packages(self, dependency):
if dep.name == extra_dep.name: constraint = dependency.constraint
dep.activate()
return package.clone()
def find_packages(
self, name, constraint=None, extras=None, allow_prereleases=False
):
name = name.lower()
packages = [] packages = []
ignored_pre_release_packages = [] ignored_pre_release_packages = []
if extras is None:
extras = []
if constraint is None: if constraint is None:
constraint = "*" constraint = "*"
if not isinstance(constraint, VersionConstraint): if not isinstance(constraint, VersionConstraint):
constraint = parse_constraint(constraint) constraint = parse_constraint(constraint)
allow_prereleases = dependency.allows_prereleases
if isinstance(constraint, VersionRange): if isinstance(constraint, VersionRange):
if ( if (
constraint.max is not None constraint.max is not None
...@@ -65,7 +55,7 @@ class Repository(BaseRepository): ...@@ -65,7 +55,7 @@ class Repository(BaseRepository):
allow_prereleases = True allow_prereleases = True
for package in self.packages: for package in self.packages:
if name == package.name: if dependency.name == package.name:
if ( if (
package.is_prerelease() package.is_prerelease()
and not allow_prereleases and not allow_prereleases
...@@ -79,19 +69,6 @@ class Repository(BaseRepository): ...@@ -79,19 +69,6 @@ class Repository(BaseRepository):
continue continue
if constraint.allows(package.version): if constraint.allows(package.version):
for dep in package.requires:
for extra in extras:
if extra not in package.extras:
continue
reqs = package.extras[extra]
for req in reqs:
if req.name == dep.name:
dep.activate()
if extras:
package.requires_extras = extras
packages.append(package) packages.append(package)
return packages or ignored_pre_release_packages return packages or ignored_pre_release_packages
......
import os
from typing import Union from typing import Union
from clikit.api.io import IO from clikit.api.io import IO
...@@ -84,18 +86,35 @@ class Exporter(object): ...@@ -84,18 +86,35 @@ class Exporter(object):
package.source_url, package.source_reference, package.name package.source_url, package.source_reference, package.name
) )
elif package.source_type in ["directory", "file", "url"]: elif package.source_type in ["directory", "file", "url"]:
url = package.source_url
if package.source_type == "file": if package.source_type == "file":
dependency = FileDependency(package.name, Path(package.source_url)) dependency = FileDependency(
package.name,
Path(package.source_url),
base=self._poetry.locker.lock.path.parent,
)
url = Path(
os.path.relpath(
url, self._poetry.locker.lock.path.parent.as_posix()
)
).as_posix()
elif package.source_type == "directory": elif package.source_type == "directory":
dependency = DirectoryDependency( dependency = DirectoryDependency(
package.name, Path(package.source_url) package.name,
Path(package.source_url),
base=self._poetry.locker.lock.path.parent,
) )
url = Path(
os.path.relpath(
url, self._poetry.locker.lock.path.parent.as_posix()
)
).as_posix()
else: else:
dependency = URLDependency(package.name, package.source_url) dependency = URLDependency(package.name, package.source_url)
dependency.marker = package.marker dependency.marker = package.marker
line = "{}".format(package.source_url) line = "{}".format(url)
if package.develop and package.source_type == "directory": if package.develop and package.source_type == "directory":
line = "-e " + line line = "-e " + line
else: else:
......
...@@ -10,6 +10,7 @@ from typing import Optional ...@@ -10,6 +10,7 @@ from typing import Optional
import requests import requests
from poetry.config.config import Config from poetry.config.config import Config
from poetry.core.packages.package import Package
from poetry.core.version import Version from poetry.core.version import Version
from poetry.utils._compat import Path from poetry.utils._compat import Path
...@@ -100,3 +101,15 @@ def download_file( ...@@ -100,3 +101,15 @@ def download_file(
for chunk in response.iter_content(chunk_size=chunk_size): for chunk in response.iter_content(chunk_size=chunk_size):
if chunk: if chunk:
f.write(chunk) f.write(chunk)
def get_package_version_display_string(
package, root=None
): # type: (Package, Optional[Path]) -> str
if package.source_type in ["file", "directory"] and root:
return "{} {}".format(
package.version,
Path(os.path.relpath(package.source_url, root.as_posix())).as_posix(),
)
return package.full_pretty_version
from typing import Union from typing import Union
from poetry.core.packages import Dependency
from poetry.core.packages import Package from poetry.core.packages import Package
from poetry.core.semver import Version from poetry.core.semver import Version
from poetry.core.semver import parse_constraint
class VersionSelector(object): class VersionSelector(object):
...@@ -21,27 +19,27 @@ class VersionSelector(object): ...@@ -21,27 +19,27 @@ class VersionSelector(object):
Given a package name and optional version, Given a package name and optional version,
returns the latest Package that matches returns the latest Package that matches
""" """
if target_package_version: from poetry.factory import Factory
constraint = parse_constraint(target_package_version)
else: dependency = Factory.create_dependency(
constraint = parse_constraint("*") package_name,
{
candidates = self._pool.find_packages( "version": target_package_version or "*",
package_name, constraint, allow_prereleases=True, repository=source "allow_prereleases": allow_prereleases,
"source": source,
},
) )
candidates = self._pool.find_packages(dependency)
only_prereleases = all([c.version.is_prerelease() for c in candidates]) only_prereleases = all([c.version.is_prerelease() for c in candidates])
if not candidates: if not candidates:
return False return False
dependency = Dependency(package_name, constraint)
package = None package = None
for candidate in candidates: for candidate in candidates:
if ( if (
candidate.is_prerelease() candidate.is_prerelease()
and not dependency.allows_prereleases() and not dependency.allows_prereleases()
and not allow_prereleases
and not only_prereleases and not only_prereleases
): ):
continue continue
......
...@@ -24,7 +24,7 @@ classifiers = [ ...@@ -24,7 +24,7 @@ classifiers = [
[tool.poetry.dependencies] [tool.poetry.dependencies]
python = "~2.7 || ^3.5" python = "~2.7 || ^3.5"
poetry-core = "^1.0.0a9" poetry-core = "^1.0.0b1"
cleo = "^0.8.1" cleo = "^0.8.1"
clikit = "^0.6.2" clikit = "^0.6.2"
crashtest = { version = "^0.3.0", python = "^3.6" } crashtest = { version = "^0.3.0", python = "^3.6" }
......
from cleo.testers import CommandTester from cleo.testers import CommandTester
from poetry.factory import Factory
from tests.helpers import get_package from tests.helpers import get_package
...@@ -8,7 +9,7 @@ def test_debug_resolve_gives_resolution_results(app, repo): ...@@ -8,7 +9,7 @@ def test_debug_resolve_gives_resolution_results(app, repo):
tester = CommandTester(command) tester = CommandTester(command)
cachy2 = get_package("cachy", "0.2.0") cachy2 = get_package("cachy", "0.2.0")
cachy2.add_dependency("msgpack-python", ">=0.5 <0.6") cachy2.add_dependency(Factory.create_dependency("msgpack-python", ">=0.5 <0.6"))
repo.add_package(get_package("cachy", "0.1.0")) repo.add_package(get_package("cachy", "0.1.0"))
repo.add_package(cachy2) repo.add_package(cachy2)
...@@ -33,7 +34,7 @@ def test_debug_resolve_tree_option_gives_the_dependency_tree(app, repo): ...@@ -33,7 +34,7 @@ def test_debug_resolve_tree_option_gives_the_dependency_tree(app, repo):
tester = CommandTester(command) tester = CommandTester(command)
cachy2 = get_package("cachy", "0.2.0") cachy2 = get_package("cachy", "0.2.0")
cachy2.add_dependency("msgpack-python", ">=0.5 <0.6") cachy2.add_dependency(Factory.create_dependency("msgpack-python", ">=0.5 <0.6"))
repo.add_package(get_package("cachy", "0.1.0")) repo.add_package(get_package("cachy", "0.1.0"))
repo.add_package(cachy2) repo.add_package(cachy2)
......
...@@ -300,12 +300,13 @@ Package operations: 2 installs, 0 updates, 0 removals ...@@ -300,12 +300,13 @@ Package operations: 2 installs, 0 updates, 0 removals
def test_add_directory_constraint(app, repo, tester, mocker): def test_add_directory_constraint(app, repo, tester, mocker):
p = mocker.patch("poetry.utils._compat.Path.cwd") p = mocker.patch("poetry.utils._compat.Path.cwd")
p.return_value = Path(__file__) / ".." p.return_value = Path(__file__).parent
repo.add_package(get_package("pendulum", "1.4.4")) repo.add_package(get_package("pendulum", "1.4.4"))
repo.add_package(get_package("cleo", "0.6.5")) repo.add_package(get_package("cleo", "0.6.5"))
tester.execute("../git/github.com/demo/demo") path = "../git/github.com/demo/demo"
tester.execute("{}".format(path))
expected = """\ expected = """\
...@@ -317,8 +318,10 @@ Writing lock file ...@@ -317,8 +318,10 @@ Writing lock file
Package operations: 2 installs, 0 updates, 0 removals Package operations: 2 installs, 0 updates, 0 removals
• Installing pendulum (1.4.4) • Installing pendulum (1.4.4)
• Installing demo (0.1.2 ../git/github.com/demo/demo) • Installing demo (0.1.2 {})
""" """.format(
app.poetry.file.parent.joinpath(path).resolve().as_posix()
)
assert expected == tester.io.fetch_output() assert expected == tester.io.fetch_output()
assert 2 == tester._command.installer.executor.installations_count assert 2 == tester._command.installer.executor.installations_count
...@@ -335,7 +338,8 @@ def test_add_directory_with_poetry(app, repo, tester, mocker): ...@@ -335,7 +338,8 @@ def test_add_directory_with_poetry(app, repo, tester, mocker):
repo.add_package(get_package("pendulum", "1.4.4")) repo.add_package(get_package("pendulum", "1.4.4"))
tester.execute("../git/github.com/demo/pyproject-demo") path = "../git/github.com/demo/pyproject-demo"
tester.execute("{}".format(path))
expected = """\ expected = """\
...@@ -347,8 +351,10 @@ Writing lock file ...@@ -347,8 +351,10 @@ Writing lock file
Package operations: 2 installs, 0 updates, 0 removals Package operations: 2 installs, 0 updates, 0 removals
• Installing pendulum (1.4.4) • Installing pendulum (1.4.4)
• Installing demo (0.1.2 ../git/github.com/demo/pyproject-demo) • Installing demo (0.1.2 {})
""" """.format(
app.poetry.file.parent.joinpath(path).resolve().as_posix()
)
assert expected == tester.io.fetch_output() assert expected == tester.io.fetch_output()
assert 2 == tester._command.installer.executor.installations_count assert 2 == tester._command.installer.executor.installations_count
...@@ -360,7 +366,8 @@ def test_add_file_constraint_wheel(app, repo, tester, mocker, poetry): ...@@ -360,7 +366,8 @@ def test_add_file_constraint_wheel(app, repo, tester, mocker, poetry):
repo.add_package(get_package("pendulum", "1.4.4")) repo.add_package(get_package("pendulum", "1.4.4"))
tester.execute("../distributions/demo-0.1.0-py2.py3-none-any.whl") path = "../distributions/demo-0.1.0-py2.py3-none-any.whl"
tester.execute("{}".format(path))
expected = """\ expected = """\
...@@ -372,8 +379,10 @@ Writing lock file ...@@ -372,8 +379,10 @@ Writing lock file
Package operations: 2 installs, 0 updates, 0 removals Package operations: 2 installs, 0 updates, 0 removals
• Installing pendulum (1.4.4) • Installing pendulum (1.4.4)
• Installing demo (0.1.0 ../distributions/demo-0.1.0-py2.py3-none-any.whl) • Installing demo (0.1.0 {})
""" """.format(
app.poetry.file.parent.joinpath(path).resolve().as_posix()
)
assert expected == tester.io.fetch_output() assert expected == tester.io.fetch_output()
assert 2 == tester._command.installer.executor.installations_count assert 2 == tester._command.installer.executor.installations_count
...@@ -392,7 +401,8 @@ def test_add_file_constraint_sdist(app, repo, tester, mocker): ...@@ -392,7 +401,8 @@ def test_add_file_constraint_sdist(app, repo, tester, mocker):
repo.add_package(get_package("pendulum", "1.4.4")) repo.add_package(get_package("pendulum", "1.4.4"))
tester.execute("../distributions/demo-0.1.0.tar.gz") path = "../distributions/demo-0.1.0.tar.gz"
tester.execute("{}".format(path))
expected = """\ expected = """\
...@@ -404,8 +414,10 @@ Writing lock file ...@@ -404,8 +414,10 @@ Writing lock file
Package operations: 2 installs, 0 updates, 0 removals Package operations: 2 installs, 0 updates, 0 removals
• Installing pendulum (1.4.4) • Installing pendulum (1.4.4)
• Installing demo (0.1.0 ../distributions/demo-0.1.0.tar.gz) • Installing demo (0.1.0 {})
""" """.format(
app.poetry.file.parent.joinpath(path).resolve().as_posix()
)
assert expected == tester.io.fetch_output() assert expected == tester.io.fetch_output()
assert 2 == tester._command.installer.executor.installations_count assert 2 == tester._command.installer.executor.installations_count
...@@ -1076,7 +1088,8 @@ def test_add_directory_constraint_old_installer( ...@@ -1076,7 +1088,8 @@ def test_add_directory_constraint_old_installer(
repo.add_package(get_package("pendulum", "1.4.4")) repo.add_package(get_package("pendulum", "1.4.4"))
repo.add_package(get_package("cleo", "0.6.5")) repo.add_package(get_package("cleo", "0.6.5"))
old_tester.execute("../git/github.com/demo/demo") path = "../git/github.com/demo/demo"
old_tester.execute("{}".format(path))
expected = """\ expected = """\
...@@ -1088,8 +1101,10 @@ Writing lock file ...@@ -1088,8 +1101,10 @@ Writing lock file
Package operations: 2 installs, 0 updates, 0 removals Package operations: 2 installs, 0 updates, 0 removals
- Installing pendulum (1.4.4) - Installing pendulum (1.4.4)
- Installing demo (0.1.2 ../git/github.com/demo/demo) - Installing demo (0.1.2 {})
""" """.format(
app.poetry.file.parent.joinpath(path).resolve().as_posix()
)
assert expected == old_tester.io.fetch_output() assert expected == old_tester.io.fetch_output()
...@@ -1109,7 +1124,8 @@ def test_add_directory_with_poetry_old_installer( ...@@ -1109,7 +1124,8 @@ def test_add_directory_with_poetry_old_installer(
repo.add_package(get_package("pendulum", "1.4.4")) repo.add_package(get_package("pendulum", "1.4.4"))
old_tester.execute("../git/github.com/demo/pyproject-demo") path = "../git/github.com/demo/pyproject-demo"
old_tester.execute("{}".format(path))
expected = """\ expected = """\
...@@ -1121,8 +1137,10 @@ Writing lock file ...@@ -1121,8 +1137,10 @@ Writing lock file
Package operations: 2 installs, 0 updates, 0 removals Package operations: 2 installs, 0 updates, 0 removals
- Installing pendulum (1.4.4) - Installing pendulum (1.4.4)
- Installing demo (0.1.2 ../git/github.com/demo/pyproject-demo) - Installing demo (0.1.2 {})
""" """.format(
app.poetry.file.parent.joinpath(path).resolve().as_posix()
)
assert expected == old_tester.io.fetch_output() assert expected == old_tester.io.fetch_output()
...@@ -1137,7 +1155,8 @@ def test_add_file_constraint_wheel_old_installer( ...@@ -1137,7 +1155,8 @@ def test_add_file_constraint_wheel_old_installer(
repo.add_package(get_package("pendulum", "1.4.4")) repo.add_package(get_package("pendulum", "1.4.4"))
old_tester.execute("../distributions/demo-0.1.0-py2.py3-none-any.whl") path = "../distributions/demo-0.1.0-py2.py3-none-any.whl"
old_tester.execute("{}".format(path))
expected = """\ expected = """\
...@@ -1149,8 +1168,10 @@ Writing lock file ...@@ -1149,8 +1168,10 @@ Writing lock file
Package operations: 2 installs, 0 updates, 0 removals Package operations: 2 installs, 0 updates, 0 removals
- Installing pendulum (1.4.4) - Installing pendulum (1.4.4)
- Installing demo (0.1.0 ../distributions/demo-0.1.0-py2.py3-none-any.whl) - Installing demo (0.1.0 {})
""" """.format(
app.poetry.file.parent.joinpath(path).resolve().as_posix()
)
assert expected == old_tester.io.fetch_output() assert expected == old_tester.io.fetch_output()
...@@ -1172,7 +1193,8 @@ def test_add_file_constraint_sdist_old_installer( ...@@ -1172,7 +1193,8 @@ def test_add_file_constraint_sdist_old_installer(
repo.add_package(get_package("pendulum", "1.4.4")) repo.add_package(get_package("pendulum", "1.4.4"))
old_tester.execute("../distributions/demo-0.1.0.tar.gz") path = "../distributions/demo-0.1.0.tar.gz"
old_tester.execute("{}".format(path))
expected = """\ expected = """\
...@@ -1184,8 +1206,10 @@ Writing lock file ...@@ -1184,8 +1206,10 @@ Writing lock file
Package operations: 2 installs, 0 updates, 0 removals Package operations: 2 installs, 0 updates, 0 removals
- Installing pendulum (1.4.4) - Installing pendulum (1.4.4)
- Installing demo (0.1.0 ../distributions/demo-0.1.0.tar.gz) - Installing demo (0.1.0 {})
""" """.format(
app.poetry.file.parent.joinpath(path).resolve().as_posix()
)
assert expected == old_tester.io.fetch_output() assert expected == old_tester.io.fetch_output()
......
...@@ -3,6 +3,7 @@ import pytest ...@@ -3,6 +3,7 @@ import pytest
from cleo.testers import CommandTester from cleo.testers import CommandTester
from clikit.formatter.ansi_formatter import AnsiFormatter from clikit.formatter.ansi_formatter import AnsiFormatter
from poetry.factory import Factory
from tests.helpers import get_package from tests.helpers import get_package
...@@ -1067,10 +1068,10 @@ def test_show_tree(app, poetry, installed): ...@@ -1067,10 +1068,10 @@ def test_show_tree(app, poetry, installed):
command = app.find("show") command = app.find("show")
tester = CommandTester(command) tester = CommandTester(command)
poetry.package.add_dependency("cachy", "^0.2.0") poetry.package.add_dependency(Factory.create_dependency("cachy", "^0.2.0"))
cachy2 = get_package("cachy", "0.2.0") cachy2 = get_package("cachy", "0.2.0")
cachy2.add_dependency("msgpack-python", ">=0.5 <0.6") cachy2.add_dependency(Factory.create_dependency("msgpack-python", ">=0.5 <0.6"))
installed.add_package(cachy2) installed.add_package(cachy2)
......
...@@ -181,14 +181,11 @@ class Poetry(BasePoetry): ...@@ -181,14 +181,11 @@ class Poetry(BasePoetry):
class Repository(BaseRepository): class Repository(BaseRepository):
def find_packages( def find_packages(self, dependency):
self, name, constraint=None, extras=None, allow_prereleases=False packages = super(Repository, self).find_packages(dependency)
):
packages = super(Repository, self).find_packages(
name, constraint, extras, allow_prereleases
)
if len(packages) == 0: if len(packages) == 0:
raise PackageNotFound("Package [{}] not found.".format(name)) raise PackageNotFound("Package [{}] not found.".format(dependency.name))
return packages return packages
def find_links_for_package(self, package): def find_links_for_package(self, package):
......
...@@ -14,23 +14,21 @@ bar = ["tomlkit"] ...@@ -14,23 +14,21 @@ bar = ["tomlkit"]
foo = ["cleo"] foo = ["cleo"]
[package.source] [package.source]
reference = ""
type = "file" type = "file"
url = "../../distributions/demo-0.1.0-py2.py3-none-any.whl" url = "../distributions/demo-0.1.0-py2.py3-none-any.whl"
[[package]] [[package]]
category = "main" category = "main"
description = "This is a description" description = "This is a description"
develop = true develop = false
name = "inner-directory-project" name = "inner-directory-project"
optional = false optional = false
python-versions = "*" python-versions = "*"
version = "1.2.4" version = "1.2.4"
[package.source] [package.source]
reference = ""
type = "directory" type = "directory"
url = "../project_with_transitive_file_dependencies/inner-directory-project" url = "project_with_transitive_file_dependencies/inner-directory-project"
[[package]] [[package]]
category = "main" category = "main"
...@@ -43,7 +41,7 @@ version = "1.4.4" ...@@ -43,7 +41,7 @@ version = "1.4.4"
[[package]] [[package]]
category = "main" category = "main"
description = "This is a description" description = "This is a description"
develop = true develop = false
name = "project-with-extras" name = "project-with-extras"
optional = false optional = false
python-versions = "*" python-versions = "*"
...@@ -54,14 +52,13 @@ extras_a = ["pendulum (>=1.4.4)"] ...@@ -54,14 +52,13 @@ extras_a = ["pendulum (>=1.4.4)"]
extras_b = ["cachy (>=0.2.0)"] extras_b = ["cachy (>=0.2.0)"]
[package.source] [package.source]
reference = ""
type = "directory" type = "directory"
url = "../project_with_extras" url = "../project_with_extras"
[[package]] [[package]]
category = "main" category = "main"
description = "This is a description" description = "This is a description"
develop = true develop = false
name = "project-with-transitive-directory-dependencies" name = "project-with-transitive-directory-dependencies"
optional = false optional = false
python-versions = "*" python-versions = "*"
...@@ -72,14 +69,13 @@ project-with-extras = "1.2.3" ...@@ -72,14 +69,13 @@ project-with-extras = "1.2.3"
project-with-transitive-file-dependencies = "1.2.3" project-with-transitive-file-dependencies = "1.2.3"
[package.source] [package.source]
reference = ""
type = "directory" type = "directory"
url = "project_with_transitive_directory_dependencies" url = "project_with_transitive_directory_dependencies"
[[package]] [[package]]
category = "main" category = "main"
description = "This is a description" description = "This is a description"
develop = true develop = false
name = "project-with-transitive-file-dependencies" name = "project-with-transitive-file-dependencies"
optional = false optional = false
python-versions = "*" python-versions = "*"
...@@ -90,7 +86,6 @@ demo = "0.1.0" ...@@ -90,7 +86,6 @@ demo = "0.1.0"
inner-directory-project = "1.2.4" inner-directory-project = "1.2.4"
[package.source] [package.source]
reference = ""
type = "directory" type = "directory"
url = "project_with_transitive_file_dependencies" url = "project_with_transitive_file_dependencies"
......
...@@ -9,7 +9,7 @@ version = "1.4.4" ...@@ -9,7 +9,7 @@ version = "1.4.4"
[[package]] [[package]]
category = "main" category = "main"
description = "This is a description" description = "This is a description"
develop = true develop = false
name = "project-with-extras" name = "project-with-extras"
optional = false optional = false
python-versions = "*" python-versions = "*"
...@@ -23,7 +23,6 @@ extras_a = ["pendulum (>=1.4.4)"] ...@@ -23,7 +23,6 @@ extras_a = ["pendulum (>=1.4.4)"]
extras_b = ["cachy (>=0.2.0)"] extras_b = ["cachy (>=0.2.0)"]
[package.source] [package.source]
reference = ""
type = "directory" type = "directory"
url = "tests/fixtures/project_with_extras" url = "tests/fixtures/project_with_extras"
......
...@@ -9,7 +9,7 @@ python-versions = "*" ...@@ -9,7 +9,7 @@ python-versions = "*"
[[package]] [[package]]
name = "my-package" name = "my-package"
version = "0.1.2" version = "0.1.2"
develop = true develop = false
description = "Demo project." description = "Demo project."
category = "main" category = "main"
optional = false optional = false
...@@ -17,7 +17,6 @@ python-versions = "*" ...@@ -17,7 +17,6 @@ python-versions = "*"
[package.source] [package.source]
type = "directory" type = "directory"
reference = ""
url = "tests/fixtures/project_with_setup" url = "tests/fixtures/project_with_setup"
[package.dependencies] [package.dependencies]
......
...@@ -14,21 +14,19 @@ bar = ["tomlkit"] ...@@ -14,21 +14,19 @@ bar = ["tomlkit"]
foo = ["cleo"] foo = ["cleo"]
[package.source] [package.source]
reference = ""
type = "file" type = "file"
url = "../distributions/demo-0.1.0-py2.py3-none-any.whl" url = "../distributions/demo-0.1.0-py2.py3-none-any.whl"
[[package]] [[package]]
category = "main" category = "main"
description = "This is a description" description = "This is a description"
develop = true develop = false
name = "inner-directory-project" name = "inner-directory-project"
optional = false optional = false
python-versions = "*" python-versions = "*"
version = "1.2.4" version = "1.2.4"
[package.source] [package.source]
reference = ""
type = "directory" type = "directory"
url = "project_with_transitive_file_dependencies/inner-directory-project" url = "project_with_transitive_file_dependencies/inner-directory-project"
...@@ -43,7 +41,7 @@ version = "1.4.4" ...@@ -43,7 +41,7 @@ version = "1.4.4"
[[package]] [[package]]
category = "main" category = "main"
description = "This is a description" description = "This is a description"
develop = true develop = false
name = "project-with-transitive-file-dependencies" name = "project-with-transitive-file-dependencies"
optional = false optional = false
python-versions = "*" python-versions = "*"
...@@ -54,7 +52,6 @@ demo = "0.1.0" ...@@ -54,7 +52,6 @@ demo = "0.1.0"
inner-directory-project = "1.2.4" inner-directory-project = "1.2.4"
[package.source] [package.source]
reference = ""
type = "directory" type = "directory"
url = "project_with_transitive_file_dependencies" url = "project_with_transitive_file_dependencies"
......
...@@ -8,7 +8,6 @@ python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" ...@@ -8,7 +8,6 @@ python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
[package.source] [package.source]
type = "file" type = "file"
reference = ""
url = "tests/fixtures/distributions/demo-0.1.0-py2.py3-none-any.whl" url = "tests/fixtures/distributions/demo-0.1.0-py2.py3-none-any.whl"
[package.dependencies] [package.dependencies]
......
...@@ -8,7 +8,6 @@ python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" ...@@ -8,7 +8,6 @@ python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
[package.source] [package.source]
type = "url" type = "url"
reference = ""
url = "https://python-poetry.org/distributions/demo-0.1.0-py2.py3-none-any.whl" url = "https://python-poetry.org/distributions/demo-0.1.0-py2.py3-none-any.whl"
[package.dependencies] [package.dependencies]
......
...@@ -8,7 +8,6 @@ python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" ...@@ -8,7 +8,6 @@ python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
[package.source] [package.source]
type = "file" type = "file"
reference = ""
url = "tests/fixtures/wheel_with_no_requires_dist/demo-0.1.0-py2.py3-none-any.whl" url = "tests/fixtures/wheel_with_no_requires_dist/demo-0.1.0-py2.py3-none-any.whl"
[metadata] [metadata]
......
...@@ -89,9 +89,13 @@ def test_chooser_chooses_universal_wheel_link_if_available( ...@@ -89,9 +89,13 @@ def test_chooser_chooses_universal_wheel_link_if_available(
package = Package("pytest", "3.5.0") package = Package("pytest", "3.5.0")
if source_type == "legacy": if source_type == "legacy":
package.source_type = "legacy" package = Package(
package.source_reference = "foo" package.name,
package.source_url = "https://foo.bar/simple/" package.version.text,
source_type="legacy",
source_reference="foo",
source_url="https://foo.bar/simple/",
)
link = chooser.choose_for(package) link = chooser.choose_for(package)
...@@ -106,9 +110,13 @@ def test_chooser_chooses_specific_python_universal_wheel_link_if_available( ...@@ -106,9 +110,13 @@ def test_chooser_chooses_specific_python_universal_wheel_link_if_available(
package = Package("isort", "4.3.4") package = Package("isort", "4.3.4")
if source_type == "legacy": if source_type == "legacy":
package.source_type = "legacy" package = Package(
package.source_reference = "foo" package.name,
package.source_url = "https://foo.bar/simple/" package.version.text,
source_type="legacy",
source_reference="foo",
source_url="https://foo.bar/simple/",
)
link = chooser.choose_for(package) link = chooser.choose_for(package)
...@@ -126,9 +134,13 @@ def test_chooser_chooses_system_specific_wheel_link_if_available( ...@@ -126,9 +134,13 @@ def test_chooser_chooses_system_specific_wheel_link_if_available(
package = Package("pyyaml", "3.13.0") package = Package("pyyaml", "3.13.0")
if source_type == "legacy": if source_type == "legacy":
package.source_type = "legacy" package = Package(
package.source_reference = "foo" package.name,
package.source_url = "https://foo.bar/simple/" package.version.text,
source_type="legacy",
source_reference="foo",
source_url="https://foo.bar/simple/",
)
link = chooser.choose_for(package) link = chooser.choose_for(package)
...@@ -143,9 +155,13 @@ def test_chooser_chooses_sdist_if_no_compatible_wheel_link_is_available( ...@@ -143,9 +155,13 @@ def test_chooser_chooses_sdist_if_no_compatible_wheel_link_is_available(
package = Package("pyyaml", "3.13.0") package = Package("pyyaml", "3.13.0")
if source_type == "legacy": if source_type == "legacy":
package.source_type = "legacy" package = Package(
package.source_reference = "foo" package.name,
package.source_url = "https://foo.bar/simple/" package.version.text,
source_type="legacy",
source_reference="foo",
source_url="https://foo.bar/simple/",
)
link = chooser.choose_for(package) link = chooser.choose_for(package)
...@@ -159,16 +175,22 @@ def test_chooser_chooses_distributions_that_match_the_package_hashes( ...@@ -159,16 +175,22 @@ def test_chooser_chooses_distributions_that_match_the_package_hashes(
chooser = Chooser(pool, env) chooser = Chooser(pool, env)
package = Package("isort", "4.3.4") package = Package("isort", "4.3.4")
package.files = [ files = [
{ {
"hash": "sha256:b9c40e9750f3d77e6e4d441d8b0266cf555e7cdabdcff33c4fd06366ca761ef8", "hash": "sha256:b9c40e9750f3d77e6e4d441d8b0266cf555e7cdabdcff33c4fd06366ca761ef8",
"filename": "isort-4.3.4.tar.gz", "filename": "isort-4.3.4.tar.gz",
} }
] ]
if source_type == "legacy": if source_type == "legacy":
package.source_type = "legacy" package = Package(
package.source_reference = "foo" package.name,
package.source_url = "https://foo.bar/simple/" package.version.text,
source_type="legacy",
source_reference="foo",
source_url="https://foo.bar/simple/",
)
package.files = files
link = chooser.choose_for(package) link = chooser.choose_for(package)
......
...@@ -65,26 +65,35 @@ def test_execute_executes_a_batch_of_operations( ...@@ -65,26 +65,35 @@ def test_execute_executes_a_batch_of_operations(
env = MockEnv(path=Path(tmp_dir)) env = MockEnv(path=Path(tmp_dir))
executor = Executor(env, pool, config, io) executor = Executor(env, pool, config, io)
file_package = Package("demo", "0.1.0") file_package = Package(
file_package.source_type = "file" "demo",
file_package.source_url = str( "0.1.0",
Path(__file__) source_type="file",
source_url=Path(__file__)
.parent.parent.joinpath( .parent.parent.joinpath(
"fixtures/distributions/demo-0.1.0-py2.py3-none-any.whl" "fixtures/distributions/demo-0.1.0-py2.py3-none-any.whl"
) )
.resolve() .resolve()
.as_posix(),
) )
directory_package = Package("simple-project", "1.2.3") directory_package = Package(
directory_package.source_type = "directory" "simple-project",
directory_package.source_url = str( "1.2.3",
Path(__file__).parent.parent.joinpath("fixtures/simple_project").resolve() source_type="directory",
source_url=Path(__file__)
.parent.parent.joinpath("fixtures/simple_project")
.resolve()
.as_posix(),
) )
git_package = Package("demo", "0.1.0") git_package = Package(
git_package.source_type = "git" "demo",
git_package.source_reference = "master" "0.1.0",
git_package.source_url = "https://github.com/demo/demo.git" source_type="git",
source_reference="master",
source_url="https://github.com/demo/demo.git",
)
assert 0 == executor.execute( assert 0 == executor.execute(
[ [
......
...@@ -13,10 +13,14 @@ from poetry.utils.env import NullEnv ...@@ -13,10 +13,14 @@ from poetry.utils.env import NullEnv
@pytest.fixture @pytest.fixture
def package_git(): def package_git():
package = Package("demo", "1.0.0") package = Package(
package.source_type = "git" "demo",
package.source_url = "git@github.com:demo/demo.git" "1.0.0",
package.source_reference = "master" source_type="git",
source_url="git@github.com:demo/demo.git",
source_reference="master",
)
return package return package
...@@ -54,9 +58,12 @@ def test_requirement(installer): ...@@ -54,9 +58,12 @@ def test_requirement(installer):
def test_requirement_source_type_url(): def test_requirement_source_type_url():
installer = PipInstaller(NullEnv(), NullIO(), Pool()) installer = PipInstaller(NullEnv(), NullIO(), Pool())
foo = Package("foo", "0.0.0") foo = Package(
foo.source_type = "url" "foo",
foo.source_url = "https://somehwere.com/releases/foo-1.0.0.tar.gz" "0.0.0",
source_type="url",
source_url="https://somehwere.com/releases/foo-1.0.0.tar.gz",
)
result = installer.requirement(foo, formatted=True) result = installer.requirement(foo, formatted=True)
expected = "{}#egg={}".format(foo.source_url, foo.name) expected = "{}#egg={}".format(foo.source_url, foo.name)
...@@ -79,14 +86,20 @@ def test_install_with_non_pypi_default_repository(pool, installer): ...@@ -79,14 +86,20 @@ def test_install_with_non_pypi_default_repository(pool, installer):
pool.add_repository(default, default=True) pool.add_repository(default, default=True)
pool.add_repository(another) pool.add_repository(another)
foo = Package("foo", "0.0.0") foo = Package(
foo.source_type = "legacy" "foo",
foo.source_reference = default._name "0.0.0",
foo.source_url = default._url source_type="legacy",
bar = Package("bar", "0.1.0") source_reference=default.name,
bar.source_type = "legacy" source_url=default.url,
bar.source_reference = another._name )
bar.source_url = another._url bar = Package(
"bar",
"0.1.0",
source_type="legacy",
source_reference=another.name,
source_url=another.url,
)
installer.install(foo) installer.install(foo)
installer.install(bar) installer.install(bar)
...@@ -104,10 +117,13 @@ def test_install_with_cert(): ...@@ -104,10 +117,13 @@ def test_install_with_cert():
installer = PipInstaller(null_env, NullIO(), pool) installer = PipInstaller(null_env, NullIO(), pool)
foo = Package("foo", "0.0.0") foo = Package(
foo.source_type = "legacy" "foo",
foo.source_reference = default._name "0.0.0",
foo.source_url = default._url source_type="legacy",
source_reference=default.name,
source_url=default.url,
)
installer.install(foo) installer.install(foo)
...@@ -133,10 +149,13 @@ def test_install_with_client_cert(): ...@@ -133,10 +149,13 @@ def test_install_with_client_cert():
installer = PipInstaller(null_env, NullIO(), pool) installer = PipInstaller(null_env, NullIO(), pool)
foo = Package("foo", "0.0.0") foo = Package(
foo.source_type = "legacy" "foo",
foo.source_reference = default._name "0.0.0",
foo.source_url = default._url source_type="legacy",
source_reference=default.name,
source_url=default.url,
)
installer.install(foo) installer.install(foo)
...@@ -161,11 +180,13 @@ def test_uninstall_git_package_nspkg_pth_cleanup(mocker, tmp_venv, pool): ...@@ -161,11 +180,13 @@ def test_uninstall_git_package_nspkg_pth_cleanup(mocker, tmp_venv, pool):
installer = PipInstaller(tmp_venv, NullIO(), pool) installer = PipInstaller(tmp_venv, NullIO(), pool)
# use a namepspace package # use a namepspace package
package = Package("namespace-package-one", "1.0.0") package = Package(
package.source_type = "git" "namespace-package-one",
package.source_url = "https://github.com/demo/namespace-package-one.git" "1.0.0",
package.source_reference = "master" source_type="git",
package.develop = True source_url="https://github.com/demo/namespace-package-one.git",
source_reference="master",
)
# we do this here because the virtual env might not be usable if failure case is triggered # we do this here because the virtual env might not be usable if failure case is triggered
pth_file_candidate = tmp_venv.site_packages / "{}-nspkg.pth".format(package.name) pth_file_candidate = tmp_venv.site_packages / "{}-nspkg.pth".format(package.name)
......
from poetry.core.packages import Package from poetry.core.packages import Package
from poetry.factory import Factory
from poetry.mixology.failure import SolveFailure from poetry.mixology.failure import SolveFailure
from poetry.mixology.version_solver import VersionSolver from poetry.mixology.version_solver import VersionSolver
from poetry.packages import DependencyPackage from poetry.packages import DependencyPackage
...@@ -11,7 +12,7 @@ def add_to_repo(repository, name, version, deps=None, python=None): ...@@ -11,7 +12,7 @@ def add_to_repo(repository, name, version, deps=None, python=None):
if deps: if deps:
for dep_name, dep_constraint in deps.items(): for dep_name, dep_constraint in deps.items():
package.add_dependency(dep_name, dep_constraint) package.add_dependency(Factory.create_dependency(dep_name, dep_constraint))
repository.add_package(package) repository.add_package(package)
......
from poetry.factory import Factory
from ..helpers import add_to_repo from ..helpers import add_to_repo
from ..helpers import check_solver_result from ..helpers import check_solver_result
def test_circular_dependency_on_older_version(root, provider, repo): def test_circular_dependency_on_older_version(root, provider, repo):
root.add_dependency("a", ">=1.0.0") root.add_dependency(Factory.create_dependency("a", ">=1.0.0"))
add_to_repo(repo, "a", "1.0.0") add_to_repo(repo, "a", "1.0.0")
add_to_repo(repo, "a", "2.0.0", deps={"b": "1.0.0"}) add_to_repo(repo, "a", "2.0.0", deps={"b": "1.0.0"})
...@@ -13,8 +15,8 @@ def test_circular_dependency_on_older_version(root, provider, repo): ...@@ -13,8 +15,8 @@ def test_circular_dependency_on_older_version(root, provider, repo):
def test_diamond_dependency_graph(root, provider, repo): def test_diamond_dependency_graph(root, provider, repo):
root.add_dependency("a", "*") root.add_dependency(Factory.create_dependency("a", "*"))
root.add_dependency("b", "*") root.add_dependency(Factory.create_dependency("b", "*"))
add_to_repo(repo, "a", "2.0.0", deps={"c": "^1.0.0"}) add_to_repo(repo, "a", "2.0.0", deps={"c": "^1.0.0"})
add_to_repo(repo, "a", "1.0.0") add_to_repo(repo, "a", "1.0.0")
...@@ -33,8 +35,8 @@ def test_backjumps_after_partial_satisfier(root, provider, repo): ...@@ -33,8 +35,8 @@ def test_backjumps_after_partial_satisfier(root, provider, repo):
# c 2.0.0 is incompatible with y 2.0.0 because it requires x 1.0.0, but that # c 2.0.0 is incompatible with y 2.0.0 because it requires x 1.0.0, but that
# requirement only exists because of both a and b. The solver should be able # requirement only exists because of both a and b. The solver should be able
# to deduce c 2.0.0's incompatibility and select c 1.0.0 instead. # to deduce c 2.0.0's incompatibility and select c 1.0.0 instead.
root.add_dependency("c", "*") root.add_dependency(Factory.create_dependency("c", "*"))
root.add_dependency("y", "^2.0.0") root.add_dependency(Factory.create_dependency("y", "^2.0.0"))
add_to_repo(repo, "a", "1.0.0", deps={"x": ">=1.0.0"}) add_to_repo(repo, "a", "1.0.0", deps={"x": ">=1.0.0"})
add_to_repo(repo, "b", "1.0.0", deps={"x": "<2.0.0"}) add_to_repo(repo, "b", "1.0.0", deps={"x": "<2.0.0"})
...@@ -56,7 +58,7 @@ def test_rolls_back_leaf_versions_first(root, provider, repo): ...@@ -56,7 +58,7 @@ def test_rolls_back_leaf_versions_first(root, provider, repo):
# The latest versions of a and b disagree on c. An older version of either # The latest versions of a and b disagree on c. An older version of either
# will resolve the problem. This test validates that b, which is farther # will resolve the problem. This test validates that b, which is farther
# in the dependency graph from myapp is downgraded first. # in the dependency graph from myapp is downgraded first.
root.add_dependency("a", "*") root.add_dependency(Factory.create_dependency("a", "*"))
add_to_repo(repo, "a", "1.0.0", deps={"b": "*"}) add_to_repo(repo, "a", "1.0.0", deps={"b": "*"})
add_to_repo(repo, "a", "2.0.0", deps={"b": "*", "c": "2.0.0"}) add_to_repo(repo, "a", "2.0.0", deps={"b": "*", "c": "2.0.0"})
...@@ -71,7 +73,7 @@ def test_rolls_back_leaf_versions_first(root, provider, repo): ...@@ -71,7 +73,7 @@ def test_rolls_back_leaf_versions_first(root, provider, repo):
def test_simple_transitive(root, provider, repo): def test_simple_transitive(root, provider, repo):
# Only one version of baz, so foo and bar will have to downgrade # Only one version of baz, so foo and bar will have to downgrade
# until they reach it # until they reach it
root.add_dependency("foo", "*") root.add_dependency(Factory.create_dependency("foo", "*"))
add_to_repo(repo, "foo", "1.0.0", deps={"bar": "1.0.0"}) add_to_repo(repo, "foo", "1.0.0", deps={"bar": "1.0.0"})
add_to_repo(repo, "foo", "2.0.0", deps={"bar": "2.0.0"}) add_to_repo(repo, "foo", "2.0.0", deps={"bar": "2.0.0"})
...@@ -93,8 +95,8 @@ def test_backjump_to_nearer_unsatisfied_package(root, provider, repo): ...@@ -93,8 +95,8 @@ def test_backjump_to_nearer_unsatisfied_package(root, provider, repo):
# a-2.0.0 whose dependency on c-2.0.0-nonexistent led to the problem. We # a-2.0.0 whose dependency on c-2.0.0-nonexistent led to the problem. We
# make sure b has more versions than a so that the solver tries a first # make sure b has more versions than a so that the solver tries a first
# since it sorts sibling dependencies by number of versions. # since it sorts sibling dependencies by number of versions.
root.add_dependency("a", "*") root.add_dependency(Factory.create_dependency("a", "*"))
root.add_dependency("b", "*") root.add_dependency(Factory.create_dependency("b", "*"))
add_to_repo(repo, "a", "1.0.0", deps={"c": "1.0.0"}) add_to_repo(repo, "a", "1.0.0", deps={"c": "1.0.0"})
add_to_repo(repo, "a", "2.0.0", deps={"c": "2.0.0-nonexistent"}) add_to_repo(repo, "a", "2.0.0", deps={"c": "2.0.0-nonexistent"})
...@@ -114,8 +116,8 @@ def test_traverse_into_package_with_fewer_versions_first(root, provider, repo): ...@@ -114,8 +116,8 @@ def test_traverse_into_package_with_fewer_versions_first(root, provider, repo):
# downgraded once). The chosen one depends on which dep is traversed first. # downgraded once). The chosen one depends on which dep is traversed first.
# Since b has fewer versions, it will be traversed first, which means a will # Since b has fewer versions, it will be traversed first, which means a will
# come later. Since later selections are revised first, a gets downgraded. # come later. Since later selections are revised first, a gets downgraded.
root.add_dependency("a", "*") root.add_dependency(Factory.create_dependency("a", "*"))
root.add_dependency("b", "*") root.add_dependency(Factory.create_dependency("b", "*"))
add_to_repo(repo, "a", "1.0.0", deps={"c": "*"}) add_to_repo(repo, "a", "1.0.0", deps={"c": "*"})
add_to_repo(repo, "a", "2.0.0", deps={"c": "*"}) add_to_repo(repo, "a", "2.0.0", deps={"c": "*"})
...@@ -133,8 +135,8 @@ def test_traverse_into_package_with_fewer_versions_first(root, provider, repo): ...@@ -133,8 +135,8 @@ def test_traverse_into_package_with_fewer_versions_first(root, provider, repo):
def test_backjump_past_failed_package_on_disjoint_constraint(root, provider, repo): def test_backjump_past_failed_package_on_disjoint_constraint(root, provider, repo):
root.add_dependency("a", "*") root.add_dependency(Factory.create_dependency("a", "*"))
root.add_dependency("foo", ">2.0.0") root.add_dependency(Factory.create_dependency("foo", ">2.0.0"))
add_to_repo(repo, "a", "1.0.0", deps={"foo": "*"}) # ok add_to_repo(repo, "a", "1.0.0", deps={"foo": "*"}) # ok
add_to_repo( add_to_repo(
......
from poetry.factory import Factory
from ..helpers import add_to_repo from ..helpers import add_to_repo
from ..helpers import check_solver_result from ..helpers import check_solver_result
def test_simple_dependencies(root, provider, repo): def test_simple_dependencies(root, provider, repo):
root.add_dependency("a", "1.0.0") root.add_dependency(Factory.create_dependency("a", "1.0.0"))
root.add_dependency("b", "1.0.0") root.add_dependency(Factory.create_dependency("b", "1.0.0"))
add_to_repo(repo, "a", "1.0.0", deps={"aa": "1.0.0", "ab": "1.0.0"}) add_to_repo(repo, "a", "1.0.0", deps={"aa": "1.0.0", "ab": "1.0.0"})
add_to_repo(repo, "b", "1.0.0", deps={"ba": "1.0.0", "bb": "1.0.0"}) add_to_repo(repo, "b", "1.0.0", deps={"ba": "1.0.0", "bb": "1.0.0"})
...@@ -28,8 +30,8 @@ def test_simple_dependencies(root, provider, repo): ...@@ -28,8 +30,8 @@ def test_simple_dependencies(root, provider, repo):
def test_shared_dependencies_with_overlapping_constraints(root, provider, repo): def test_shared_dependencies_with_overlapping_constraints(root, provider, repo):
root.add_dependency("a", "1.0.0") root.add_dependency(Factory.create_dependency("a", "1.0.0"))
root.add_dependency("b", "1.0.0") root.add_dependency(Factory.create_dependency("b", "1.0.0"))
add_to_repo(repo, "a", "1.0.0", deps={"shared": ">=2.0.0 <4.0.0"}) add_to_repo(repo, "a", "1.0.0", deps={"shared": ">=2.0.0 <4.0.0"})
add_to_repo(repo, "b", "1.0.0", deps={"shared": ">=3.0.0 <5.0.0"}) add_to_repo(repo, "b", "1.0.0", deps={"shared": ">=3.0.0 <5.0.0"})
...@@ -45,8 +47,8 @@ def test_shared_dependencies_with_overlapping_constraints(root, provider, repo): ...@@ -45,8 +47,8 @@ def test_shared_dependencies_with_overlapping_constraints(root, provider, repo):
def test_shared_dependency_where_dependent_version_affects_other_dependencies( def test_shared_dependency_where_dependent_version_affects_other_dependencies(
root, provider, repo root, provider, repo
): ):
root.add_dependency("foo", "<=1.0.2") root.add_dependency(Factory.create_dependency("foo", "<=1.0.2"))
root.add_dependency("bar", "1.0.0") root.add_dependency(Factory.create_dependency("bar", "1.0.0"))
add_to_repo(repo, "foo", "1.0.0") add_to_repo(repo, "foo", "1.0.0")
add_to_repo(repo, "foo", "1.0.1", deps={"bang": "1.0.0"}) add_to_repo(repo, "foo", "1.0.1", deps={"bang": "1.0.0"})
...@@ -63,7 +65,7 @@ def test_shared_dependency_where_dependent_version_affects_other_dependencies( ...@@ -63,7 +65,7 @@ def test_shared_dependency_where_dependent_version_affects_other_dependencies(
def test_circular_dependency(root, provider, repo): def test_circular_dependency(root, provider, repo):
root.add_dependency("foo", "1.0.0") root.add_dependency(Factory.create_dependency("foo", "1.0.0"))
add_to_repo(repo, "foo", "1.0.0", deps={"bar": "1.0.0"}) add_to_repo(repo, "foo", "1.0.0", deps={"bar": "1.0.0"})
add_to_repo(repo, "bar", "1.0.0", deps={"foo": "1.0.0"}) add_to_repo(repo, "bar", "1.0.0", deps={"foo": "1.0.0"})
......
from poetry.factory import Factory
from ..helpers import add_to_repo from ..helpers import add_to_repo
from ..helpers import check_solver_result from ..helpers import check_solver_result
def test_dependency_does_not_match_root_python_constraint(root, provider, repo): def test_dependency_does_not_match_root_python_constraint(root, provider, repo):
provider.set_package_python_versions("^3.6") provider.set_package_python_versions("^3.6")
root.add_dependency("foo", "*") root.add_dependency(Factory.create_dependency("foo", "*"))
add_to_repo(repo, "foo", "1.0.0", python="<3.5") add_to_repo(repo, "foo", "1.0.0", python="<3.5")
......
from poetry.factory import Factory
from ..helpers import add_to_repo from ..helpers import add_to_repo
from ..helpers import check_solver_result from ..helpers import check_solver_result
def test_no_version_matching_constraint(root, provider, repo): def test_no_version_matching_constraint(root, provider, repo):
root.add_dependency("foo", "^1.0") root.add_dependency(Factory.create_dependency("foo", "^1.0"))
add_to_repo(repo, "foo", "2.0.0") add_to_repo(repo, "foo", "2.0.0")
add_to_repo(repo, "foo", "2.1.3") add_to_repo(repo, "foo", "2.1.3")
...@@ -19,8 +21,8 @@ def test_no_version_matching_constraint(root, provider, repo): ...@@ -19,8 +21,8 @@ def test_no_version_matching_constraint(root, provider, repo):
def test_no_version_that_matches_combined_constraints(root, provider, repo): def test_no_version_that_matches_combined_constraints(root, provider, repo):
root.add_dependency("foo", "1.0.0") root.add_dependency(Factory.create_dependency("foo", "1.0.0"))
root.add_dependency("bar", "1.0.0") root.add_dependency(Factory.create_dependency("bar", "1.0.0"))
add_to_repo(repo, "foo", "1.0.0", deps={"shared": ">=2.0.0 <3.0.0"}) add_to_repo(repo, "foo", "1.0.0", deps={"shared": ">=2.0.0 <3.0.0"})
add_to_repo(repo, "bar", "1.0.0", deps={"shared": ">=2.9.0 <4.0.0"}) add_to_repo(repo, "bar", "1.0.0", deps={"shared": ">=2.9.0 <4.0.0"})
...@@ -37,8 +39,8 @@ So, because myapp depends on both foo (1.0.0) and bar (1.0.0), version solving f ...@@ -37,8 +39,8 @@ So, because myapp depends on both foo (1.0.0) and bar (1.0.0), version solving f
def test_disjoint_constraints(root, provider, repo): def test_disjoint_constraints(root, provider, repo):
root.add_dependency("foo", "1.0.0") root.add_dependency(Factory.create_dependency("foo", "1.0.0"))
root.add_dependency("bar", "1.0.0") root.add_dependency(Factory.create_dependency("bar", "1.0.0"))
add_to_repo(repo, "foo", "1.0.0", deps={"shared": "<=2.0.0"}) add_to_repo(repo, "foo", "1.0.0", deps={"shared": "<=2.0.0"})
add_to_repo(repo, "bar", "1.0.0", deps={"shared": ">3.0.0"}) add_to_repo(repo, "bar", "1.0.0", deps={"shared": ">3.0.0"})
...@@ -55,8 +57,8 @@ So, because myapp depends on both foo (1.0.0) and bar (1.0.0), version solving f ...@@ -55,8 +57,8 @@ So, because myapp depends on both foo (1.0.0) and bar (1.0.0), version solving f
def test_disjoint_root_constraints(root, provider, repo): def test_disjoint_root_constraints(root, provider, repo):
root.add_dependency("foo", "1.0.0") root.add_dependency(Factory.create_dependency("foo", "1.0.0"))
root.add_dependency("foo", "2.0.0") root.add_dependency(Factory.create_dependency("foo", "2.0.0"))
add_to_repo(repo, "foo", "1.0.0") add_to_repo(repo, "foo", "1.0.0")
add_to_repo(repo, "foo", "2.0.0") add_to_repo(repo, "foo", "2.0.0")
...@@ -68,8 +70,8 @@ Because myapp depends on both foo (1.0.0) and foo (2.0.0), version solving faile ...@@ -68,8 +70,8 @@ Because myapp depends on both foo (1.0.0) and foo (2.0.0), version solving faile
def test_no_valid_solution(root, provider, repo): def test_no_valid_solution(root, provider, repo):
root.add_dependency("a") root.add_dependency(Factory.create_dependency("a", "*"))
root.add_dependency("b") root.add_dependency(Factory.create_dependency("b", "*"))
add_to_repo(repo, "a", "1.0.0", deps={"b": "1.0.0"}) add_to_repo(repo, "a", "1.0.0", deps={"b": "1.0.0"})
add_to_repo(repo, "a", "2.0.0", deps={"b": "2.0.0"}) add_to_repo(repo, "a", "2.0.0", deps={"b": "2.0.0"})
......
from poetry.factory import Factory
from ...helpers import get_package from ...helpers import get_package
from ..helpers import add_to_repo from ..helpers import add_to_repo
from ..helpers import check_solver_result from ..helpers import check_solver_result
def test_with_compatible_locked_dependencies(root, provider, repo): def test_with_compatible_locked_dependencies(root, provider, repo):
root.add_dependency("foo", "*") root.add_dependency(Factory.create_dependency("foo", "*"))
add_to_repo(repo, "foo", "1.0.0", deps={"bar": "1.0.0"}) add_to_repo(repo, "foo", "1.0.0", deps={"bar": "1.0.0"})
add_to_repo(repo, "foo", "1.0.1", deps={"bar": "1.0.1"}) add_to_repo(repo, "foo", "1.0.1", deps={"bar": "1.0.1"})
...@@ -22,7 +24,7 @@ def test_with_compatible_locked_dependencies(root, provider, repo): ...@@ -22,7 +24,7 @@ def test_with_compatible_locked_dependencies(root, provider, repo):
def test_with_incompatible_locked_dependencies(root, provider, repo): def test_with_incompatible_locked_dependencies(root, provider, repo):
root.add_dependency("foo", ">1.0.1") root.add_dependency(Factory.create_dependency("foo", ">1.0.1"))
add_to_repo(repo, "foo", "1.0.0", deps={"bar": "1.0.0"}) add_to_repo(repo, "foo", "1.0.0", deps={"bar": "1.0.0"})
add_to_repo(repo, "foo", "1.0.1", deps={"bar": "1.0.1"}) add_to_repo(repo, "foo", "1.0.1", deps={"bar": "1.0.1"})
...@@ -40,7 +42,7 @@ def test_with_incompatible_locked_dependencies(root, provider, repo): ...@@ -40,7 +42,7 @@ def test_with_incompatible_locked_dependencies(root, provider, repo):
def test_with_unrelated_locked_dependencies(root, provider, repo): def test_with_unrelated_locked_dependencies(root, provider, repo):
root.add_dependency("foo", "*") root.add_dependency(Factory.create_dependency("foo", "*"))
add_to_repo(repo, "foo", "1.0.0", deps={"bar": "1.0.0"}) add_to_repo(repo, "foo", "1.0.0", deps={"bar": "1.0.0"})
add_to_repo(repo, "foo", "1.0.1", deps={"bar": "1.0.1"}) add_to_repo(repo, "foo", "1.0.1", deps={"bar": "1.0.1"})
...@@ -61,8 +63,8 @@ def test_with_unrelated_locked_dependencies(root, provider, repo): ...@@ -61,8 +63,8 @@ def test_with_unrelated_locked_dependencies(root, provider, repo):
def test_unlocks_dependencies_if_necessary_to_ensure_that_a_new_dependency_is_statisfied( def test_unlocks_dependencies_if_necessary_to_ensure_that_a_new_dependency_is_statisfied(
root, provider, repo root, provider, repo
): ):
root.add_dependency("foo") root.add_dependency(Factory.create_dependency("foo", "*"))
root.add_dependency("newdep", "2.0.0") root.add_dependency(Factory.create_dependency("newdep", "2.0.0"))
add_to_repo(repo, "foo", "1.0.0", deps={"bar": "<2.0.0"}) add_to_repo(repo, "foo", "1.0.0", deps={"bar": "<2.0.0"})
add_to_repo(repo, "bar", "1.0.0", deps={"baz": "<2.0.0"}) add_to_repo(repo, "bar", "1.0.0", deps={"baz": "<2.0.0"})
...@@ -94,8 +96,8 @@ def test_unlocks_dependencies_if_necessary_to_ensure_that_a_new_dependency_is_st ...@@ -94,8 +96,8 @@ def test_unlocks_dependencies_if_necessary_to_ensure_that_a_new_dependency_is_st
def test_with_compatible_locked_dependencies_use_latest(root, provider, repo): def test_with_compatible_locked_dependencies_use_latest(root, provider, repo):
root.add_dependency("foo", "*") root.add_dependency(Factory.create_dependency("foo", "*"))
root.add_dependency("baz", "*") root.add_dependency(Factory.create_dependency("baz", "*"))
add_to_repo(repo, "foo", "1.0.0", deps={"bar": "1.0.0"}) add_to_repo(repo, "foo", "1.0.0", deps={"bar": "1.0.0"})
add_to_repo(repo, "foo", "1.0.1", deps={"bar": "1.0.1"}) add_to_repo(repo, "foo", "1.0.1", deps={"bar": "1.0.1"})
......
...@@ -4,8 +4,10 @@ import tempfile ...@@ -4,8 +4,10 @@ import tempfile
import pytest import pytest
import tomlkit import tomlkit
from poetry.core.packages.package import Package
from poetry.core.packages.project_package import ProjectPackage from poetry.core.packages.project_package import ProjectPackage
from poetry.core.semver.version import Version from poetry.core.semver.version import Version
from poetry.factory import Factory
from poetry.packages.locker import Locker from poetry.packages.locker import Locker
from ..helpers import get_dependency from ..helpers import get_dependency
...@@ -28,9 +30,17 @@ def root(): ...@@ -28,9 +30,17 @@ def root():
def test_lock_file_data_is_ordered(locker, root): def test_lock_file_data_is_ordered(locker, root):
package_a = get_package("A", "1.0.0") package_a = get_package("A", "1.0.0")
package_a.add_dependency("B", "^1.0") package_a.add_dependency(Factory.create_dependency("B", "^1.0"))
package_a.files = [{"file": "foo", "hash": "456"}, {"file": "bar", "hash": "123"}] package_a.files = [{"file": "foo", "hash": "456"}, {"file": "bar", "hash": "123"}]
packages = [package_a, get_package("B", "1.2")] package_git = Package(
"git-package",
"1.2.3",
source_type="git",
source_url="https://github.com/python-poetry/poetry.git",
source_reference="develop",
source_resolved_reference="123456",
)
packages = [package_a, get_package("B", "1.2"), package_git]
locker.set_lock_data(root, packages) locker.set_lock_data(root, packages)
...@@ -38,28 +48,42 @@ def test_lock_file_data_is_ordered(locker, root): ...@@ -38,28 +48,42 @@ def test_lock_file_data_is_ordered(locker, root):
content = f.read() content = f.read()
expected = """[[package]] expected = """[[package]]
category = "main"
description = ""
name = "A" name = "A"
version = "1.0.0"
description = ""
category = "main"
optional = false optional = false
python-versions = "*" python-versions = "*"
version = "1.0.0"
[package.dependencies] [package.dependencies]
B = "^1.0" B = "^1.0"
[[package]] [[package]]
name = "B"
version = "1.2"
description = ""
category = "main" category = "main"
optional = false
python-versions = "*"
[[package]]
name = "git-package"
version = "1.2.3"
description = "" description = ""
name = "B" category = "main"
optional = false optional = false
python-versions = "*" python-versions = "*"
version = "1.2"
[package.source]
type = "git"
url = "https://github.com/python-poetry/poetry.git"
reference = "develop"
resolved_reference = "123456"
[metadata] [metadata]
content-hash = "115cf985d932e9bf5f540555bbdd75decbb62cac81e399375fc19f6277f8c1d8"
lock-version = "1.1" lock-version = "1.1"
python-versions = "*" python-versions = "*"
content-hash = "115cf985d932e9bf5f540555bbdd75decbb62cac81e399375fc19f6277f8c1d8"
[metadata.files] [metadata.files]
A = [ A = [
...@@ -67,6 +91,7 @@ A = [ ...@@ -67,6 +91,7 @@ A = [
{file = "foo", hash = "456"}, {file = "foo", hash = "456"},
] ]
B = [] B = []
git-package = []
""" """
assert expected == content assert expected == content
...@@ -75,12 +100,12 @@ B = [] ...@@ -75,12 +100,12 @@ B = []
def test_locker_properly_loads_extras(locker): def test_locker_properly_loads_extras(locker):
content = """\ content = """\
[[package]] [[package]]
category = "main"
description = "httplib2 caching for requests"
name = "cachecontrol" name = "cachecontrol"
version = "0.12.5"
description = "httplib2 caching for requests"
category = "main"
optional = false optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
version = "0.12.5"
[package.dependencies] [package.dependencies]
msgpack = "*" msgpack = "*"
...@@ -95,9 +120,9 @@ filecache = ["lockfile (>=0.9)"] ...@@ -95,9 +120,9 @@ filecache = ["lockfile (>=0.9)"]
redis = ["redis (>=2.10.5)"] redis = ["redis (>=2.10.5)"]
[metadata] [metadata]
content-hash = "c3d07fca33fba542ef2b2a4d75bf5b48d892d21a830e2ad9c952ba5123a52f77"
lock-version = "1.1" lock-version = "1.1"
python-versions = "~2.7 || ^3.4" python-versions = "~2.7 || ^3.4"
content-hash = "c3d07fca33fba542ef2b2a4d75bf5b48d892d21a830e2ad9c952ba5123a52f77"
[metadata.files] [metadata.files]
cachecontrol = [] cachecontrol = []
...@@ -127,17 +152,17 @@ def test_lock_packages_with_null_description(locker, root): ...@@ -127,17 +152,17 @@ def test_lock_packages_with_null_description(locker, root):
content = f.read() content = f.read()
expected = """[[package]] expected = """[[package]]
category = "main"
description = ""
name = "A" name = "A"
version = "1.0.0"
description = ""
category = "main"
optional = false optional = false
python-versions = "*" python-versions = "*"
version = "1.0.0"
[metadata] [metadata]
content-hash = "115cf985d932e9bf5f540555bbdd75decbb62cac81e399375fc19f6277f8c1d8"
lock-version = "1.1" lock-version = "1.1"
python-versions = "*" python-versions = "*"
content-hash = "115cf985d932e9bf5f540555bbdd75decbb62cac81e399375fc19f6277f8c1d8"
[metadata.files] [metadata.files]
A = [] A = []
...@@ -148,36 +173,36 @@ A = [] ...@@ -148,36 +173,36 @@ A = []
def test_lock_file_should_not_have_mixed_types(locker, root): def test_lock_file_should_not_have_mixed_types(locker, root):
package_a = get_package("A", "1.0.0") package_a = get_package("A", "1.0.0")
package_a.add_dependency("B", "^1.0.0") package_a.add_dependency(Factory.create_dependency("B", "^1.0.0"))
package_a.add_dependency("B", {"version": ">=1.0.0", "optional": True}) package_a.add_dependency(
Factory.create_dependency("B", {"version": ">=1.0.0", "optional": True})
)
package_a.requires[-1].activate() package_a.requires[-1].activate()
package_a.extras["foo"] = [get_dependency("B", ">=1.0.0")] package_a.extras["foo"] = [get_dependency("B", ">=1.0.0")]
locker.set_lock_data(root, [package_a]) locker.set_lock_data(root, [package_a])
expected = """[[package]] expected = """[[package]]
category = "main"
description = ""
name = "A" name = "A"
version = "1.0.0"
description = ""
category = "main"
optional = false optional = false
python-versions = "*" python-versions = "*"
version = "1.0.0"
[package.dependencies] [package.dependencies]
[[package.dependencies.B]] B = [
version = "^1.0.0" {version = "^1.0.0"},
{version = ">=1.0.0", optional = true},
[[package.dependencies.B]] ]
optional = true
version = ">=1.0.0"
[package.extras] [package.extras]
foo = ["B (>=1.0.0)"] foo = ["B (>=1.0.0)"]
[metadata] [metadata]
content-hash = "115cf985d932e9bf5f540555bbdd75decbb62cac81e399375fc19f6277f8c1d8"
lock-version = "1.1" lock-version = "1.1"
python-versions = "*" python-versions = "*"
content-hash = "115cf985d932e9bf5f540555bbdd75decbb62cac81e399375fc19f6277f8c1d8"
[metadata.files] [metadata.files]
A = [] A = []
...@@ -191,12 +216,12 @@ A = [] ...@@ -191,12 +216,12 @@ A = []
def test_reading_lock_file_should_raise_an_error_on_invalid_data(locker): def test_reading_lock_file_should_raise_an_error_on_invalid_data(locker):
content = u"""[[package]] content = u"""[[package]]
category = "main"
description = ""
name = "A" name = "A"
version = "1.0.0"
description = ""
category = "main"
optional = false optional = false
python-versions = "*" python-versions = "*"
version = "1.0.0"
[package.extras] [package.extras]
foo = ["bar"] foo = ["bar"]
...@@ -205,9 +230,9 @@ foo = ["bar"] ...@@ -205,9 +230,9 @@ foo = ["bar"]
foo = ["bar"] foo = ["bar"]
[metadata] [metadata]
content-hash = "115cf985d932e9bf5f540555bbdd75decbb62cac81e399375fc19f6277f8c1d8"
lock-version = "1.1" lock-version = "1.1"
python-versions = "*" python-versions = "*"
content-hash = "115cf985d932e9bf5f540555bbdd75decbb62cac81e399375fc19f6277f8c1d8"
[metadata.files] [metadata.files]
A = [] A = []
...@@ -222,9 +247,13 @@ A = [] ...@@ -222,9 +247,13 @@ A = []
def test_locking_legacy_repository_package_should_include_source_section(root, locker): def test_locking_legacy_repository_package_should_include_source_section(root, locker):
package_a = get_package("A", "1.0.0") package_a = Package(
package_a.source_url = "https://foo.bar" "A",
package_a.source_reference = "legacy" "1.0.0",
source_type="legacy",
source_url="https://foo.bar",
source_reference="legacy",
)
packages = [package_a] packages = [package_a]
locker.set_lock_data(root, packages) locker.set_lock_data(root, packages)
...@@ -233,21 +262,22 @@ def test_locking_legacy_repository_package_should_include_source_section(root, l ...@@ -233,21 +262,22 @@ def test_locking_legacy_repository_package_should_include_source_section(root, l
content = f.read() content = f.read()
expected = """[[package]] expected = """[[package]]
category = "main"
description = ""
name = "A" name = "A"
version = "1.0.0"
description = ""
category = "main"
optional = false optional = false
python-versions = "*" python-versions = "*"
version = "1.0.0"
[package.source] [package.source]
reference = "legacy" type = "legacy"
url = "https://foo.bar" url = "https://foo.bar"
reference = "legacy"
[metadata] [metadata]
content-hash = "115cf985d932e9bf5f540555bbdd75decbb62cac81e399375fc19f6277f8c1d8"
lock-version = "1.1" lock-version = "1.1"
python-versions = "*" python-versions = "*"
content-hash = "115cf985d932e9bf5f540555bbdd75decbb62cac81e399375fc19f6277f8c1d8"
[metadata.files] [metadata.files]
A = [] A = []
...@@ -261,9 +291,9 @@ def test_locker_should_emit_warnings_if_lock_version_is_newer_but_allowed( ...@@ -261,9 +291,9 @@ def test_locker_should_emit_warnings_if_lock_version_is_newer_but_allowed(
): ):
content = """\ content = """\
[metadata] [metadata]
content-hash = "c3d07fca33fba542ef2b2a4d75bf5b48d892d21a830e2ad9c952ba5123a52f77"
lock-version = "{version}" lock-version = "{version}"
python-versions = "~2.7 || ^3.4" python-versions = "~2.7 || ^3.4"
content-hash = "c3d07fca33fba542ef2b2a4d75bf5b48d892d21a830e2ad9c952ba5123a52f77"
[metadata.files] [metadata.files]
""".format( """.format(
...@@ -293,9 +323,9 @@ def test_locker_should_raise_an_error_if_lock_version_is_newer_and_not_allowed( ...@@ -293,9 +323,9 @@ def test_locker_should_raise_an_error_if_lock_version_is_newer_and_not_allowed(
): ):
content = """\ content = """\
[metadata] [metadata]
content-hash = "c3d07fca33fba542ef2b2a4d75bf5b48d892d21a830e2ad9c952ba5123a52f77"
lock-version = "2.0" lock-version = "2.0"
python-versions = "~2.7 || ^3.4" python-versions = "~2.7 || ^3.4"
content-hash = "c3d07fca33fba542ef2b2a4d75bf5b48d892d21a830e2ad9c952ba5123a52f77"
[metadata.files] [metadata.files]
""" """
...@@ -310,27 +340,29 @@ python-versions = "~2.7 || ^3.4" ...@@ -310,27 +340,29 @@ python-versions = "~2.7 || ^3.4"
def test_extras_dependencies_are_ordered(locker, root): def test_extras_dependencies_are_ordered(locker, root):
package_a = get_package("A", "1.0.0") package_a = get_package("A", "1.0.0")
package_a.add_dependency( package_a.add_dependency(
"B", {"version": "^1.0.0", "optional": True, "extras": ["c", "a", "b"]} Factory.create_dependency(
"B", {"version": "^1.0.0", "optional": True, "extras": ["c", "a", "b"]}
)
) )
package_a.requires[-1].activate() package_a.requires[-1].activate()
locker.set_lock_data(root, [package_a]) locker.set_lock_data(root, [package_a])
expected = """[[package]] expected = """[[package]]
category = "main"
description = ""
name = "A" name = "A"
version = "1.0.0"
description = ""
category = "main"
optional = false optional = false
python-versions = "*" python-versions = "*"
version = "1.0.0"
[package.dependencies] [package.dependencies]
B = {version = "^1.0.0", extras = ["a", "b", "c"], optional = true} B = {version = "^1.0.0", extras = ["a", "b", "c"], optional = true}
[metadata] [metadata]
content-hash = "115cf985d932e9bf5f540555bbdd75decbb62cac81e399375fc19f6277f8c1d8"
lock-version = "1.1" lock-version = "1.1"
python-versions = "*" python-versions = "*"
content-hash = "115cf985d932e9bf5f540555bbdd75decbb62cac81e399375fc19f6277f8c1d8"
[metadata.files] [metadata.files]
A = [] A = []
...@@ -351,9 +383,9 @@ def test_locker_should_neither_emit_warnings_nor_raise_error_for_lower_compatibl ...@@ -351,9 +383,9 @@ def test_locker_should_neither_emit_warnings_nor_raise_error_for_lower_compatibl
) )
content = """\ content = """\
[metadata] [metadata]
content-hash = "c3d07fca33fba542ef2b2a4d75bf5b48d892d21a830e2ad9c952ba5123a52f77"
lock-version = "{version}" lock-version = "{version}"
python-versions = "~2.7 || ^3.4" python-versions = "~2.7 || ^3.4"
content-hash = "c3d07fca33fba542ef2b2a4d75bf5b48d892d21a830e2ad9c952ba5123a52f77"
[metadata.files] [metadata.files]
""".format( """.format(
......
...@@ -156,5 +156,5 @@ def test_load_editable_with_import_package(repository): ...@@ -156,5 +156,5 @@ def test_load_editable_with_import_package(repository):
assert editable is not None assert editable is not None
assert editable.name == "editable-with-import" assert editable.name == "editable-with-import"
assert editable.version.text == "2.3.4" assert editable.version.text == "2.3.4"
assert editable.source_type == "" assert editable.source_type is None
assert editable.source_url == "" assert editable.source_url is None
...@@ -3,6 +3,7 @@ import shutil ...@@ -3,6 +3,7 @@ import shutil
import pytest import pytest
from poetry.core.packages import Dependency from poetry.core.packages import Dependency
from poetry.factory import Factory
from poetry.repositories.auth import Auth from poetry.repositories.auth import Auth
from poetry.repositories.exceptions import PackageNotFound from poetry.repositories.exceptions import PackageNotFound
from poetry.repositories.exceptions import RepositoryError from poetry.repositories.exceptions import RepositoryError
...@@ -117,7 +118,10 @@ def test_get_package_information_skips_dependencies_with_invalid_constraints(): ...@@ -117,7 +118,10 @@ def test_get_package_information_skips_dependencies_with_invalid_constraints():
package.description == "Python Language Server for the Language Server Protocol" package.description == "Python Language Server for the Language Server Protocol"
) )
assert sorted(package.requires, key=lambda r: r.name) == [ assert 19 == len(package.requires)
assert sorted(
[r for r in package.requires if not r.is_optional()], key=lambda r: r.name
) == [
Dependency("configparser", "*"), Dependency("configparser", "*"),
Dependency("future", ">=0.14.0"), Dependency("future", ">=0.14.0"),
Dependency("futures", "*"), Dependency("futures", "*"),
...@@ -142,7 +146,7 @@ def test_get_package_information_skips_dependencies_with_invalid_constraints(): ...@@ -142,7 +146,7 @@ def test_get_package_information_skips_dependencies_with_invalid_constraints():
def test_find_packages_no_prereleases(): def test_find_packages_no_prereleases():
repo = MockRepository() repo = MockRepository()
packages = repo.find_packages("pyyaml") packages = repo.find_packages(Factory.create_dependency("pyyaml", "*"))
assert len(packages) == 1 assert len(packages) == 1
...@@ -154,7 +158,7 @@ def test_find_packages_no_prereleases(): ...@@ -154,7 +158,7 @@ def test_find_packages_no_prereleases():
@pytest.mark.parametrize("constraint,count", [("*", 1), (">=1", 0), (">=19.0.0a0", 1)]) @pytest.mark.parametrize("constraint,count", [("*", 1), (">=1", 0), (">=19.0.0a0", 1)])
def test_find_packages_only_prereleases(constraint, count): def test_find_packages_only_prereleases(constraint, count):
repo = MockRepository() repo = MockRepository()
packages = repo.find_packages("black", constraint=constraint) packages = repo.find_packages(Factory.create_dependency("black", constraint))
assert len(packages) == count assert len(packages) == count
...@@ -167,7 +171,7 @@ def test_find_packages_only_prereleases(constraint, count): ...@@ -167,7 +171,7 @@ def test_find_packages_only_prereleases(constraint, count):
def test_find_packages_only_prereleases_empty_when_not_any(): def test_find_packages_only_prereleases_empty_when_not_any():
repo = MockRepository() repo = MockRepository()
packages = repo.find_packages("black", constraint=">=1") packages = repo.find_packages(Factory.create_dependency("black", ">=1"))
assert len(packages) == 0 assert len(packages) == 0
...@@ -213,6 +217,7 @@ def test_get_package_from_both_py2_and_py3_specific_wheels(): ...@@ -213,6 +217,7 @@ def test_get_package_from_both_py2_and_py3_specific_wheels():
assert "ipython" == package.name assert "ipython" == package.name
assert "5.7.0" == package.version.text assert "5.7.0" == package.version.text
assert "*" == package.python_versions assert "*" == package.python_versions
assert 26 == len(package.requires)
expected = [ expected = [
Dependency("appnope", "*"), Dependency("appnope", "*"),
...@@ -229,16 +234,17 @@ def test_get_package_from_both_py2_and_py3_specific_wheels(): ...@@ -229,16 +234,17 @@ def test_get_package_from_both_py2_and_py3_specific_wheels():
Dependency("traitlets", ">=4.2"), Dependency("traitlets", ">=4.2"),
Dependency("win-unicode-console", ">=0.5"), Dependency("win-unicode-console", ">=0.5"),
] ]
assert expected == package.requires required = [r for r in package.requires if not r.is_optional()]
assert expected == required
assert 'python_version == "2.7"' == str(package.requires[1].marker) assert 'python_version == "2.7"' == str(required[1].marker)
assert 'sys_platform == "win32" and python_version < "3.6"' == str( assert 'sys_platform == "win32" and python_version < "3.6"' == str(
package.requires[12].marker required[12].marker
) )
assert 'python_version == "2.7" or python_version == "3.3"' == str( assert 'python_version == "2.7" or python_version == "3.3"' == str(
package.requires[4].marker required[4].marker
) )
assert 'sys_platform != "win32"' == str(package.requires[5].marker) assert 'sys_platform != "win32"' == str(required[5].marker)
def test_get_package_with_dist_and_universal_py3_wheel(): def test_get_package_with_dist_and_universal_py3_wheel():
...@@ -265,7 +271,8 @@ def test_get_package_with_dist_and_universal_py3_wheel(): ...@@ -265,7 +271,8 @@ def test_get_package_with_dist_and_universal_py3_wheel():
Dependency("typing", "*"), Dependency("typing", "*"),
Dependency("win-unicode-console", ">=0.5"), Dependency("win-unicode-console", ">=0.5"),
] ]
assert expected == sorted(package.requires, key=lambda dep: dep.name) required = [r for r in package.requires if not r.is_optional()]
assert expected == sorted(required, key=lambda dep: dep.name)
def test_get_package_retrieves_non_sha256_hashes(): def test_get_package_retrieves_non_sha256_hashes():
......
...@@ -9,6 +9,7 @@ from requests.exceptions import TooManyRedirects ...@@ -9,6 +9,7 @@ from requests.exceptions import TooManyRedirects
from requests.models import Response from requests.models import Response
from poetry.core.packages import Dependency from poetry.core.packages import Dependency
from poetry.factory import Factory
from poetry.repositories.pypi_repository import PyPiRepository from poetry.repositories.pypi_repository import PyPiRepository
from poetry.utils._compat import PY35 from poetry.utils._compat import PY35
from poetry.utils._compat import Path from poetry.utils._compat import Path
...@@ -56,21 +57,21 @@ class MockRepository(PyPiRepository): ...@@ -56,21 +57,21 @@ class MockRepository(PyPiRepository):
def test_find_packages(): def test_find_packages():
repo = MockRepository() repo = MockRepository()
packages = repo.find_packages("requests", "^2.18") packages = repo.find_packages(Factory.create_dependency("requests", "^2.18"))
assert len(packages) == 5 assert len(packages) == 5
def test_find_packages_with_prereleases(): def test_find_packages_with_prereleases():
repo = MockRepository() repo = MockRepository()
packages = repo.find_packages("toga", ">=0.3.0.dev2") packages = repo.find_packages(Factory.create_dependency("toga", ">=0.3.0.dev2"))
assert len(packages) == 7 assert len(packages) == 7
def test_find_packages_does_not_select_prereleases_if_not_allowed(): def test_find_packages_does_not_select_prereleases_if_not_allowed():
repo = MockRepository() repo = MockRepository()
packages = repo.find_packages("pyyaml") packages = repo.find_packages(Factory.create_dependency("pyyaml", "*"))
assert len(packages) == 1 assert len(packages) == 1
...@@ -78,7 +79,7 @@ def test_find_packages_does_not_select_prereleases_if_not_allowed(): ...@@ -78,7 +79,7 @@ def test_find_packages_does_not_select_prereleases_if_not_allowed():
@pytest.mark.parametrize("constraint,count", [("*", 1), (">=1", 0), (">=19.0.0a0", 1)]) @pytest.mark.parametrize("constraint,count", [("*", 1), (">=1", 0), (">=19.0.0a0", 1)])
def test_find_packages_only_prereleases(constraint, count): def test_find_packages_only_prereleases(constraint, count):
repo = MockRepository() repo = MockRepository()
packages = repo.find_packages("black", constraint=constraint) packages = repo.find_packages(Factory.create_dependency("black", constraint))
assert len(packages) == count assert len(packages) == count
...@@ -89,7 +90,8 @@ def test_package(): ...@@ -89,7 +90,8 @@ def test_package():
package = repo.package("requests", "2.18.4") package = repo.package("requests", "2.18.4")
assert package.name == "requests" assert package.name == "requests"
assert len(package.requires) == 4 assert len(package.requires) == 9
assert len([r for r in package.requires if r.is_optional()]) == 5
assert len(package.extras["security"]) == 3 assert len(package.extras["security"]) == 3
assert len(package.extras["socks"]) == 2 assert len(package.extras["socks"]) == 2
...@@ -141,7 +143,8 @@ def test_fallback_can_read_setup_to_get_dependencies(): ...@@ -141,7 +143,8 @@ def test_fallback_can_read_setup_to_get_dependencies():
package = repo.package("sqlalchemy", "1.2.12") package = repo.package("sqlalchemy", "1.2.12")
assert package.name == "sqlalchemy" assert package.name == "sqlalchemy"
assert len(package.requires) == 0 assert len(package.requires) == 9
assert len([r for r in package.requires if r.is_optional()]) == 9
assert package.extras == { assert package.extras == {
"mssql_pymssql": [Dependency("pymssql", "*")], "mssql_pymssql": [Dependency("pymssql", "*")],
...@@ -162,7 +165,10 @@ def test_pypi_repository_supports_reading_bz2_files(): ...@@ -162,7 +165,10 @@ def test_pypi_repository_supports_reading_bz2_files():
package = repo.package("twisted", "18.9.0") package = repo.package("twisted", "18.9.0")
assert package.name == "twisted" assert package.name == "twisted"
assert sorted(package.requires, key=lambda r: r.name) == [ assert 28 == len(package.requires)
assert sorted(
[r for r in package.requires if not r.is_optional()], key=lambda r: r.name
) == [
Dependency("attrs", ">=17.4.0"), Dependency("attrs", ">=17.4.0"),
Dependency("Automat", ">=0.3.0"), Dependency("Automat", ">=0.3.0"),
Dependency("constantly", ">=15.1"), Dependency("constantly", ">=15.1"),
...@@ -198,7 +204,7 @@ def test_invalid_versions_ignored(): ...@@ -198,7 +204,7 @@ def test_invalid_versions_ignored():
# the json metadata for this package contains one malformed version # the json metadata for this package contains one malformed version
# and a correct one. # and a correct one.
packages = repo.find_packages("pygame-music-grid") packages = repo.find_packages(Factory.create_dependency("pygame-music-grid", "*"))
assert len(packages) == 1 assert len(packages) == 1
...@@ -228,6 +234,6 @@ def test_urls(): ...@@ -228,6 +234,6 @@ def test_urls():
def test_use_pypi_pretty_name(): def test_use_pypi_pretty_name():
repo = MockRepository(fallback=True) repo = MockRepository(fallback=True)
package = repo.find_packages("twisted") package = repo.find_packages(Factory.create_dependency("twisted", "*"))
assert len(package) == 1 assert len(package) == 1
assert package[0].pretty_name == "Twisted" assert package[0].pretty_name == "Twisted"
...@@ -55,7 +55,7 @@ def test_create_poetry(): ...@@ -55,7 +55,7 @@ def test_create_poetry():
assert not requests.is_vcs() assert not requests.is_vcs()
assert not requests.allows_prereleases() assert not requests.allows_prereleases()
assert requests.is_optional() assert requests.is_optional()
assert requests.extras == ["security"] assert requests.extras == frozenset(["security"])
pathlib2 = dependencies["pathlib2"] pathlib2 = dependencies["pathlib2"]
assert pathlib2.pretty_constraint == "^2.2" assert pathlib2.pretty_constraint == "^2.2"
......
...@@ -559,7 +559,6 @@ def test_remove_keeps_dir_if_not_deleteable(tmp_dir, manager, poetry, config, mo ...@@ -559,7 +559,6 @@ def test_remove_keeps_dir_if_not_deleteable(tmp_dir, manager, poetry, config, mo
original_rmtree = shutil.rmtree original_rmtree = shutil.rmtree
def err_on_rm_venv_only(path, *args, **kwargs): def err_on_rm_venv_only(path, *args, **kwargs):
print(path)
if path == str(venv_path): if path == str(venv_path):
raise OSError(16, "Test error") # ERRNO 16: Device or resource busy raise OSError(16, "Test error") # ERRNO 16: Device or resource busy
else: else:
......
...@@ -8,10 +8,12 @@ from poetry.repositories.auth import Auth ...@@ -8,10 +8,12 @@ from poetry.repositories.auth import Auth
from poetry.repositories.legacy_repository import LegacyRepository from poetry.repositories.legacy_repository import LegacyRepository
from poetry.utils._compat import Path from poetry.utils._compat import Path
from poetry.utils.exporter import Exporter from poetry.utils.exporter import Exporter
from poetry.utils.toml_file import TomlFile
class Locker(BaseLocker): class Locker(BaseLocker):
def __init__(self): def __init__(self):
self._lock = TomlFile(Path.cwd().joinpath("poetry.lock"))
self._locked = True self._locked = True
self._content_hash = self._get_content_hash() self._content_hash = self._get_content_hash()
......
import pytest import pytest
from poetry.core.packages import Package from poetry.core.packages import Package
from poetry.factory import Factory
from poetry.utils.extras import get_extra_package_names from poetry.utils.extras import get_extra_package_names
_PACKAGE_FOO = Package("foo", "0.1.0") _PACKAGE_FOO = Package("foo", "0.1.0")
_PACKAGE_SPAM = Package("spam", "0.2.0") _PACKAGE_SPAM = Package("spam", "0.2.0")
_PACKAGE_BAR = Package("bar", "0.3.0") _PACKAGE_BAR = Package("bar", "0.3.0")
_PACKAGE_BAR.add_dependency("foo") _PACKAGE_BAR.add_dependency(Factory.create_dependency("foo", "*"))
# recursive dependency # recursive dependency
_PACKAGE_BAZ = Package("baz", "0.4.0") _PACKAGE_BAZ = Package("baz", "0.4.0")
_PACKAGE_BAZ.add_dependency("quix") _PACKAGE_BAZ.add_dependency(Factory.create_dependency("quix", "*"))
_PACKAGE_QUIX = Package("quix", "0.5.0") _PACKAGE_QUIX = Package("quix", "0.5.0")
_PACKAGE_QUIX.add_dependency("baz") _PACKAGE_QUIX.add_dependency(Factory.create_dependency("baz", "*"))
@pytest.mark.parametrize( @pytest.mark.parametrize(
......
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