diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 30d8f5fde21..0f9f2029a1c 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -67,4 +67,4 @@ jobs: - name: Run pytest shell: bash - run: poetry run pytest -q tests + run: poetry run pytest -v tests diff --git a/poetry/console/commands/debug/resolve.py b/poetry/console/commands/debug/resolve.py index f58b09cbbb1..c4c64b483c3 100644 --- a/poetry/console/commands/debug/resolve.py +++ b/poetry/console/commands/debug/resolve.py @@ -28,9 +28,8 @@ class DebugResolveCommand(InitCommand): loggers = ["poetry.repositories.pypi_repository"] def handle(self): + from poetry.core.packages.project_package import ProjectPackage from poetry.io.null_io import NullIO - from poetry.core.packages import ProjectPackage - from poetry.installation.installer import Installer from poetry.puzzle import Solver from poetry.repositories.pool import Pool from poetry.repositories.repository import Repository @@ -106,7 +105,6 @@ def handle(self): if self.option("install"): env = EnvManager(self.poetry).get() - current_python_version = ".".join(str(v) for v in env.version_info) pool = Pool() locked_repository = Repository() for op in ops: @@ -114,11 +112,9 @@ def handle(self): pool.add_repository(locked_repository) - with package.with_python_versions(current_python_version): - installer = Installer(NullIO(), env, package, self.poetry.locker, pool) - solver = Solver(package, pool, Repository(), Repository(), NullIO()) + solver = Solver(package, pool, Repository(), Repository(), NullIO()) + with solver.use_environment(env): ops = solver.solve() - installer._filter_operations(ops, Repository()) for op in ops: if self.option("install") and op.skipped: diff --git a/poetry/installation/installer.py b/poetry/installation/installer.py index fdd785a5c02..e01703303f6 100644 --- a/poetry/installation/installer.py +++ b/poetry/installation/installer.py @@ -3,8 +3,8 @@ from clikit.api.io import IO -from poetry.core.packages.package import Package -from poetry.core.semver import parse_constraint +from poetry.core.packages.project_package import ProjectPackage +from poetry.io.null_io import NullIO from poetry.packages import Locker from poetry.puzzle import Solver from poetry.puzzle.operations import Install @@ -26,7 +26,7 @@ def __init__( self, io, # type: IO env, - package, # type: Package + package, # type: ProjectPackage locker, # type: Locker pool, # type: Pool installed=None, # type: (Union[InstalledRepository, None]) @@ -196,6 +196,37 @@ def _do_install(self, local_repo): root = root.clone() del root.dev_requires[:] + if self._io.is_verbose(): + self._io.write_line("") + self._io.write_line( + "Finding the necessary packages for the current system" + ) + + # We resolve again by only using the lock file + pool = Pool(ignore_repository_names=True) + + # Making a new repo containing the packages + # newly resolved and the ones from the current lock file + repo = Repository() + for package in local_repo.packages + locked_repository.packages: + if not repo.has_package(package): + repo.add_package(package) + + pool.add_repository(repo) + + # We whitelist all packages to be sure + # that the latest ones are picked up + whitelist = [] + for pkg in locked_repository.packages: + whitelist.append(pkg.name) + + solver = Solver( + root, pool, self._installed_repository, locked_repository, NullIO() + ) + + with solver.use_environment(self._env): + ops = solver.solve(use_latest=whitelist) + # We need to filter operations so that packages # not compatible with the current system, # or optional and not requested, are dropped @@ -411,15 +442,6 @@ def _filter_operations( if op.job_type == "uninstall": continue - current_python = parse_constraint( - ".".join(str(v) for v in self._env.version_info[:3]) - ) - if not package.python_constraint.allows( - current_python - ) or not self._env.is_valid_for_marker(package.marker): - op.skip("Not needed for the current environment") - continue - if self._update: extras = {} for extra, deps in self._package.extras.items(): diff --git a/poetry/mixology/version_solver.py b/poetry/mixology/version_solver.py index bd6d5c73f01..5331478edc7 100644 --- a/poetry/mixology/version_solver.py +++ b/poetry/mixology/version_solver.py @@ -440,6 +440,13 @@ def _get_locked(self, dependency): # type: (Dependency) -> Union[Package, None] if dependency.extras: locked.requires_extras = dependency.extras + 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 def _log(self, text): diff --git a/poetry/packages/locker.py b/poetry/packages/locker.py index 722df01245c..7fcca247587 100644 --- a/poetry/packages/locker.py +++ b/poetry/packages/locker.py @@ -244,7 +244,8 @@ def _dump_package(self, package): # type: (Package) -> dict if dependency.pretty_name not in dependencies: dependencies[dependency.pretty_name] = [] - constraint = {"version": str(dependency.pretty_constraint)} + constraint = inline_table() + constraint["version"] = str(dependency.pretty_constraint) if dependency.extras: constraint["extras"] = sorted(dependency.extras) @@ -252,8 +253,8 @@ def _dump_package(self, package): # type: (Package) -> dict if dependency.is_optional(): constraint["optional"] = True - if not dependency.python_constraint.is_any(): - constraint["python"] = str(dependency.python_constraint) + if not dependency.marker.is_any(): + constraint["markers"] = str(dependency.marker) dependencies[dependency.pretty_name].append(constraint) @@ -274,8 +275,6 @@ def _dump_package(self, package): # type: (Package) -> dict "python-versions": package.python_versions, "files": sorted(package.files, key=lambda x: x["file"]), } - if not package.marker.is_any(): - data["marker"] = str(package.marker) if package.extras: extras = {} diff --git a/poetry/puzzle/provider.py b/poetry/puzzle/provider.py index 71266538330..e56e16d68fb 100644 --- a/poetry/puzzle/provider.py +++ b/poetry/puzzle/provider.py @@ -33,6 +33,7 @@ from poetry.utils._compat import OrderedDict from poetry.utils._compat import Path from poetry.utils._compat import urlparse +from poetry.utils.env import Env from poetry.utils.helpers import download_file from poetry.utils.helpers import safe_rmtree from poetry.utils.helpers import temporary_directory @@ -52,10 +53,13 @@ class Provider: UNSAFE_PACKAGES = {"setuptools", "distribute", "pip"} - def __init__(self, package, pool, io): # type: (Package, Pool, Any) -> None + def __init__( + self, package, pool, io, env=None + ): # type: (Package, Pool, Any, Optional[Env]) -> None self._package = package self._pool = pool self._io = io + self._env = env self._python_constraint = package.python_constraint self._search_for = {} self._is_debugging = self._io.is_debug() or self._io.is_very_verbose() @@ -66,25 +70,21 @@ def __init__(self, package, pool, io): # type: (Package, Pool, Any) -> None def pool(self): # type: () -> Pool return self._pool - @property - def name_for_explicit_dependency_source(self): # type: () -> str - return "pyproject.toml" - - @property - def name_for_locking_dependency_source(self): # type: () -> str - return "poetry.lock" - def is_debugging(self): return self._is_debugging def set_overrides(self, overrides): self._overrides = overrides - def name_for(self, dependency): # type: (Dependency) -> str - """ - Returns the name for the given dependency. - """ - return dependency.name + @contextmanager + def use_environment(self, env): # type: (Env) -> Provider + original_env = self._env + + self._env = env + + yield self + + self._env = original_env def search_for(self, dependency): # type: (Dependency) -> List[Package] """ @@ -371,6 +371,7 @@ def incompatibilities_for( for dep in dependencies if dep.name not in self.UNSAFE_PACKAGES and self._package.python_constraint.allows_any(dep.python_constraint) + and (not self._env or dep.marker.validate(self._env.marker_env)) ] overrides = self._overrides.get(package, {}) @@ -426,6 +427,7 @@ def complete_package( for r in requires if self._package.python_constraint.allows_any(r.python_constraint) and r.name not in self.UNSAFE_PACKAGES + and (not self._env or r.marker.validate(self._env.marker_env)) ] overrides = self._overrides.get(package, {}) diff --git a/poetry/puzzle/solver.py b/poetry/puzzle/solver.py index 36b2b7e04e7..5ee6f5a485e 100644 --- a/poetry/puzzle/solver.py +++ b/poetry/puzzle/solver.py @@ -1,14 +1,15 @@ import time +from contextlib import contextmanager from typing import Any from typing import Dict from typing import List from poetry.core.packages import Package -from poetry.core.version.markers import AnyMarker from poetry.mixology import resolve_version from poetry.mixology.failure import SolveFailure from poetry.packages import DependencyPackage +from poetry.utils.env import Env from .exceptions import OverrideNeeded from .exceptions import SolverProblemError @@ -29,6 +30,15 @@ def __init__(self, package, pool, installed, locked, io): self._provider = Provider(self._package, self._pool, self._io) self._overrides = [] + @property + def provider(self): # type: () -> Provider + return self._provider + + @contextmanager + def use_environment(self, env): # type: (Env) -> None + with self.provider.use_environment(env): + yield + def solve(self, use_latest=None): # type: (...) -> List[Operation] with self._provider.progress(): start = time.time() @@ -157,7 +167,6 @@ def solve_in_compatibility_mode(self, overrides, use_latest=None): idx = packages.index(package) pkg = packages[idx] depths[idx] = max(depths[idx], _depths[index]) - pkg.marker = pkg.marker.union(package.marker) for dep in package.requires: if dep not in pkg.requires: @@ -189,18 +198,10 @@ def _solve(self, use_latest=None): depths = [] final_packages = [] for package in packages: - category, optional, marker, depth = self._get_tags_for_package( - package, graph - ) - - if marker is None: - marker = AnyMarker() - if marker.is_empty(): - continue + category, optional, depth = self._get_tags_for_package(package, graph) package.category = category package.optional = optional - package.marker = marker depths.append(depth) final_packages.append(package) @@ -213,25 +214,15 @@ def _build_graph( if not previous: category = "dev" optional = True - marker = package.marker else: category = dep.category optional = dep.is_optional() and not dep.is_activated() - intersection = ( - previous["marker"] - .without_extras() - .intersect(previous_dep.transitive_marker.without_extras()) - ) - intersection = intersection.intersect(package.marker.without_extras()) - - marker = intersection childrens = [] # type: List[Dict[str, Any]] graph = { "name": package.name, "category": category, "optional": optional, - "marker": marker, "children": childrens, } @@ -290,9 +281,6 @@ def _build_graph( child_graph["optional"] = True if existing: - existing["marker"] = existing["marker"].union( - child_graph["marker"] - ) continue childrens.append(child_graph) @@ -302,7 +290,6 @@ def _build_graph( def _get_tags_for_package(self, package, graph, depth=0): categories = ["dev"] optionals = [True] - markers = [] _depths = [0] children = graph["children"] @@ -310,10 +297,9 @@ def _get_tags_for_package(self, package, graph, depth=0): if child["name"] == package.name: category = child["category"] optional = child["optional"] - marker = child["marker"] _depths.append(depth) else: - (category, optional, marker, _depth) = self._get_tags_for_package( + (category, optional, _depth) = self._get_tags_for_package( package, child, depth=depth + 1 ) @@ -321,8 +307,6 @@ def _get_tags_for_package(self, package, graph, depth=0): categories.append(category) optionals.append(optional) - if marker is not None: - markers.append(marker) if "main" in categories: category = "main" @@ -333,11 +317,4 @@ def _get_tags_for_package(self, package, graph, depth=0): depth = max(*(_depths + [0])) - if not markers: - marker = None - else: - marker = markers[0] - for m in markers[1:]: - marker = marker.union(m) - - return category, optional, marker, depth + return category, optional, depth diff --git a/poetry/utils/env.py b/poetry/utils/env.py index 013483f7167..7a59cb28f75 100644 --- a/poetry/utils/env.py +++ b/poetry/utils/env.py @@ -1010,7 +1010,9 @@ def get_marker_env(self): # type: () -> Dict[str, Any] "platform_version": platform.version(), "python_full_version": platform.python_version(), "platform_python_implementation": platform.python_implementation(), - "python_version": platform.python_version()[:3], + "python_version": ".".join( + v for v in platform.python_version().split(".")[:2] + ), "sys_platform": sys.platform, "version_info": sys.version_info, } @@ -1185,6 +1187,7 @@ def __init__( is_venv=False, pip_version="19.1", sys_path=None, + marker_env=None, **kwargs ): super(MockEnv, self).__init__(**kwargs) @@ -1196,14 +1199,7 @@ def __init__( self._is_venv = is_venv self._pip_version = Version.parse(pip_version) self._sys_path = sys_path - - @property - def version_info(self): # type: () -> Tuple[int] - return self._version_info - - @property - def python_implementation(self): # type: () -> str - return self._python_implementation + self._mock_marker_env = marker_env @property def platform(self): # type: () -> str @@ -1224,5 +1220,17 @@ def sys_path(self): return self._sys_path + def get_marker_env(self): # type: () -> Dict[str, Any] + if self._mock_marker_env is not None: + return self._mock_marker_env + + marker_env = super(MockEnv, self).get_marker_env() + marker_env["python_implementation"] = self._python_implementation + marker_env["version_info"] = self._version_info + marker_env["python_version"] = ".".join(str(v) for v in self._version_info[:2]) + marker_env["sys_platform"] = self._platform + + return marker_env + def is_venv(self): # type: () -> bool return self._is_venv diff --git a/tests/console/commands/test_add.py b/tests/console/commands/test_add.py index 9a1e5036500..866715163ae 100644 --- a/tests/console/commands/test_add.py +++ b/tests/console/commands/test_add.py @@ -598,8 +598,9 @@ def test_add_constraint_with_python(app, repo, installer): assert content["dependencies"]["cachy"] == {"version": "0.2.0", "python": ">=2.7"} -def test_add_constraint_with_platform(app, repo, installer): +def test_add_constraint_with_platform(app, repo, installer, env): platform = sys.platform + env._platform = platform command = app.find("add") tester = CommandTester(command) @@ -608,7 +609,7 @@ def test_add_constraint_with_platform(app, repo, installer): repo.add_package(get_package("cachy", "0.1.0")) repo.add_package(cachy2) - tester.execute("cachy=0.2.0 --platform {}".format(platform)) + tester.execute("cachy=0.2.0 --platform {} -vvv".format(platform)) expected = """\ diff --git a/tests/installation/fixtures/old-lock.test b/tests/installation/fixtures/old-lock.test new file mode 100644 index 00000000000..e1898fbd3f1 --- /dev/null +++ b/tests/installation/fixtures/old-lock.test @@ -0,0 +1,120 @@ +[[package]] +name = "attrs" +version = "17.4.0" +description = "Classes Without Boilerplate" +category = "dev" +optional = false +python-versions = "*" + +[package.extras] +dev = ["coverage", "hypothesis", "pympler", "pytest", "six", "zope.interface", "sphinx", "zope.interface"] +docs = ["sphinx", "zope.interface"] +tests = ["coverage", "hypothesis", "pympler", "pytest", "six", "zope.interface"] + +[[package]] +name = "colorama" +version = "0.3.9" +description = "Cross-platform colored terminal text." +category = "dev" +marker = "sys_platform == \"win32\"" +optional = false +python-versions = "*" + +[[package]] +name = "funcsigs" +version = "1.0.2" +description = "Python function signatures from PEP362 for Python 2.6, 2.7 and 3.2+" +category = "dev" +marker = "python_version < \"3.0\"" +optional = false +python-versions = "*" + +[[package]] +name = "more-itertools" +version = "4.1.0" +description = "More routines for operating on iterables, beyond itertools" +category = "dev" +optional = false +python-versions = "*" + +[package.dependencies] +six = ">=1.0.0,<2.0.0" + +[[package]] +name = "pluggy" +version = "0.6.0" +description = "plugin and hook calling mechanisms for python" +category = "dev" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" + +[[package]] +name = "py" +version = "1.5.3" +description = "library with cross-python path, ini-parsing, io, code, log facilities" +category = "dev" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" + +[[package]] +name = "pytest" +version = "3.5.0" +description = "pytest: simple powerful testing with Python" +category = "dev" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" + +[package.dependencies] +py = ">=1.5.0" +six = ">=1.10.0" +attrs = ">=17.4.0" +more-itertools = ">=4.0.0" +pluggy = ">=0.5,<0.7" +funcsigs = {"version" = "*", "python" = "<3.0"} +colorama = "*" + +[[package]] +name = "six" +version = "1.11.0" +description = "Python 2 and 3 compatibility utilities" +category = "dev" +optional = false +python-versions = "*" + +[metadata] +python-versions = "*" +content-hash = "123456789" + +[metadata.files] +attrs = [ + {file = "attrs-17.4.0-py2.py3-none-any.whl", hash = "sha256:a17a9573a6f475c99b551c0e0a812707ddda1ec9653bed04c13841404ed6f450"}, + {file = "attrs-17.4.0.tar.gz", hash = "sha256:1c7960ccfd6a005cd9f7ba884e6316b5e430a3f1a6c37c5f87d8b43f83b54ec9"}, +] +colorama = [ + {file = "colorama-0.3.9-py2.py3-none-any.whl", hash = "sha256:463f8483208e921368c9f306094eb6f725c6ca42b0f97e313cb5d5512459feda"}, + {file = "colorama-0.3.9.tar.gz", hash = "sha256:48eb22f4f8461b1df5734a074b57042430fb06e1d61bd1e11b078c0fe6d7a1f1"}, +] +funcsigs = [ + {file = "funcsigs-1.0.2-py2.py3-none-any.whl", hash = "sha256:330cc27ccbf7f1e992e69fef78261dc7c6569012cf397db8d3de0234e6c937ca"}, + {file = "funcsigs-1.0.2.tar.gz", hash = "sha256:a7bb0f2cf3a3fd1ab2732cb49eba4252c2af4240442415b4abce3b87022a8f50"}, +] +more-itertools = [ + {file = "more-itertools-4.1.0.tar.gz", hash = "sha256:c9ce7eccdcb901a2c75d326ea134e0886abfbea5f93e91cc95de9507c0816c44"}, + {file = "more_itertools-4.1.0-py2-none-any.whl", hash = "sha256:11a625025954c20145b37ff6309cd54e39ca94f72f6bb9576d1195db6fa2442e"}, + {file = "more_itertools-4.1.0-py3-none-any.whl", hash = "sha256:0dd8f72eeab0d2c3bd489025bb2f6a1b8342f9b198f6fc37b52d15cfa4531fea"}, +] +pluggy = [ + {file = "pluggy-0.6.0.tar.gz", hash = "sha256:7f8ae7f5bdf75671a718d2daf0a64b7885f74510bcd98b1a0bb420eb9a9d0cff"}, +] +py = [ + {file = "py-1.5.3-py2.py3-none-any.whl", hash = "sha256:983f77f3331356039fdd792e9220b7b8ee1aa6bd2b25f567a963ff1de5a64f6a"}, + {file = "py-1.5.3.tar.gz", hash = "sha256:29c9fab495d7528e80ba1e343b958684f4ace687327e6f789a94bf3d1915f881"}, +] +pytest = [ + {file = "pytest-3.5.0-py2.py3-none-any.whl", hash = "sha256:6266f87ab64692112e5477eba395cfedda53b1933ccd29478e671e73b420c19c"}, + {file = "pytest-3.5.0.tar.gz", hash = "sha256:fae491d1874f199537fd5872b5e1f0e74a009b979df9d53d1553fd03da1703e1"}, +] +six = [ + {file = "six-1.11.0-py2.py3-none-any.whl", hash = "sha256:832dc0e10feb1aa2c68dcc57dbb658f1c7e65b9b61af69048abc87a2db00a0eb"}, + {file = "six-1.11.0.tar.gz", hash = "sha256:70e8a77beed4562e7f14fe23a786b54f6296e34344c23bc42f07b15018ff98e9"}, +] diff --git a/tests/installation/fixtures/update-with-locked-extras.test b/tests/installation/fixtures/update-with-locked-extras.test index 83aecc522d6..d34686a5a22 100644 --- a/tests/installation/fixtures/update-with-locked-extras.test +++ b/tests/installation/fixtures/update-with-locked-extras.test @@ -8,7 +8,7 @@ python-versions = "*" [package.dependencies] "B" = {version = "^1.0", optional = true} -"C" = {"version" = "^1.0", "python" = ">=2.7,<2.8"} +"C" = {version = "^1.0", markers = "python_version >= \"2.7\" and python_version < \"2.8\""} [package.extras] foo = ["b"] @@ -26,7 +26,6 @@ name = "C" version = "1.1" description = "" category = "main" -marker = "python_version >= \"2.7\" and python_version < \"2.8\"" optional = false python-versions = "*" diff --git a/tests/installation/fixtures/with-directory-dependency-poetry.test b/tests/installation/fixtures/with-directory-dependency-poetry.test index c9bd6b32c4b..59972e48be9 100644 --- a/tests/installation/fixtures/with-directory-dependency-poetry.test +++ b/tests/installation/fixtures/with-directory-dependency-poetry.test @@ -16,7 +16,7 @@ python-versions = "*" version = "1.2.3" [package.dependencies] -pendulum = {version = ">=1.4.4", optional = true} +pendulum = {version = ">=1.4.4", optional = true, markers = "extra == \"extras_a\""} [package.extras] extras_a = ["pendulum (>=1.4.4)"] diff --git a/tests/installation/fixtures/with-duplicate-dependencies-update.test b/tests/installation/fixtures/with-duplicate-dependencies-update.test index 89956f45bea..93f9afcd7e0 100644 --- a/tests/installation/fixtures/with-duplicate-dependencies-update.test +++ b/tests/installation/fixtures/with-duplicate-dependencies-update.test @@ -23,7 +23,6 @@ C = "1.5" [[package]] name = "C" version = "1.5" -marker = "python_version >= \"2.7\"" description = "" category = "main" optional = false diff --git a/tests/installation/fixtures/with-duplicate-dependencies.test b/tests/installation/fixtures/with-duplicate-dependencies.test index 7149b87d02b..32748b13e48 100644 --- a/tests/installation/fixtures/with-duplicate-dependencies.test +++ b/tests/installation/fixtures/with-duplicate-dependencies.test @@ -8,8 +8,8 @@ python-versions = "*" [package.dependencies] B = [ - {"version" = "^1.0", "python" = "<4.0"}, - {"version" = "^2.0", "python" = ">=4.0"}, + {version = "^1.0", markers = "python_version < \"4.0\""}, + {version = "^2.0", markers = "python_version >= \"4.0\""}, ] [[package]] @@ -17,7 +17,6 @@ name = "B" version = "1.0" description = "" category = "main" -marker = "python_version < \"4.0\"" optional = false python-versions = "*" @@ -29,7 +28,6 @@ name = "B" version = "2.0" description = "" category = "main" -marker = "python_version >= \"4.0\"" optional = false python-versions = "*" @@ -41,7 +39,6 @@ name = "C" version = "1.2" description = "" category = "main" -marker = "python_version < \"4.0\"" optional = false python-versions = "*" @@ -50,7 +47,6 @@ name = "C" version = "1.5" description = "" category = "main" -marker = "python_version >= \"4.0\"" optional = false python-versions = "*" diff --git a/tests/installation/fixtures/with-multiple-updates.test b/tests/installation/fixtures/with-multiple-updates.test index cacaf6954af..678e2ae8b2c 100644 --- a/tests/installation/fixtures/with-multiple-updates.test +++ b/tests/installation/fixtures/with-multiple-updates.test @@ -1,6 +1,6 @@ [[package]] name = "A" -version = "1.0" +version = "1.1" description = "" category = "main" optional = false @@ -9,17 +9,17 @@ python-versions = "*" [package.dependencies] B = ">=1.0.1" C = [ - {version = "^1.0", python = ">=2.7,<2.8"}, - {version = "^2.0", python = ">=3.4,<4.0"}, + {version = "^1.0", markers = "python_version >= \"2.7\" and python_version < \"2.8\""}, + {version = "^2.0", markers = "python_version >= \"3.4\" and python_version < \"4.0\""}, ] [[package]] name = "B" -version = "1.0.1" +version = "1.1.0" description = "" category = "main" optional = false -python-versions = ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*" +python-versions = "*" [[package]] name = "C" @@ -27,7 +27,6 @@ version = "1.0" description = "" category = "main" optional = false -marker = "python_version >= \"2.7\" and python_version < \"2.8\"" python-versions = "*" [[package]] @@ -36,7 +35,6 @@ version = "2.0" description = "" category = "main" optional = false -marker = "python_version >= \"3.4\" and python_version < \"4.0\"" python-versions = "*" [metadata] diff --git a/tests/installation/fixtures/with-optional-dependencies.test b/tests/installation/fixtures/with-optional-dependencies.test index 3e392ff9782..48d6b095861 100644 --- a/tests/installation/fixtures/with-optional-dependencies.test +++ b/tests/installation/fixtures/with-optional-dependencies.test @@ -11,7 +11,6 @@ name = "C" version = "1.3" description = "" category = "main" -marker = "python_version >= \"2.7\" and python_version < \"2.8\" or python_version >= \"3.4\" and python_version < \"4.0\"" optional = false python-versions = "*" @@ -23,7 +22,6 @@ name = "D" version = "1.4" description = "" category = "main" -marker = "python_version >= \"2.7\" and python_version < \"2.8\" or python_version >= \"3.4\" and python_version < \"4.0\"" optional = false python-versions = "*" diff --git a/tests/installation/fixtures/with-platform-dependencies.test b/tests/installation/fixtures/with-platform-dependencies.test index 260e413f701..bc91c988bd6 100644 --- a/tests/installation/fixtures/with-platform-dependencies.test +++ b/tests/installation/fixtures/with-platform-dependencies.test @@ -11,7 +11,6 @@ name = "B" version = "1.1" description = "" category = "main" -marker = "sys_platform == \"custom\"" optional = false python-versions = "*" @@ -20,7 +19,6 @@ name = "C" version = "1.3" description = "" category = "main" -marker = "sys_platform == \"darwin\"" optional = false python-versions = "*" @@ -32,7 +30,6 @@ name = "D" version = "1.4" description = "" category = "main" -marker = "sys_platform == \"darwin\"" optional = false python-versions = "*" diff --git a/tests/installation/fixtures/with-pypi-repository.test b/tests/installation/fixtures/with-pypi-repository.test index e1898fbd3f1..00b63c43c3a 100644 --- a/tests/installation/fixtures/with-pypi-repository.test +++ b/tests/installation/fixtures/with-pypi-repository.test @@ -16,7 +16,6 @@ name = "colorama" version = "0.3.9" description = "Cross-platform colored terminal text." category = "dev" -marker = "sys_platform == \"win32\"" optional = false python-versions = "*" @@ -25,7 +24,6 @@ name = "funcsigs" version = "1.0.2" description = "Python function signatures from PEP362 for Python 2.6, 2.7 and 3.2+" category = "dev" -marker = "python_version < \"3.0\"" optional = false python-versions = "*" @@ -70,8 +68,8 @@ six = ">=1.10.0" attrs = ">=17.4.0" more-itertools = ">=4.0.0" pluggy = ">=0.5,<0.7" -funcsigs = {"version" = "*", "python" = "<3.0"} -colorama = "*" +funcsigs = {"version" = "*", "markers" = "python_version < \"3.0\""} +colorama = {"version" = "*", "markers" = "sys_platform == \"win32\""} [[package]] name = "six" diff --git a/tests/installation/test_installer.py b/tests/installation/test_installer.py index dadbb6be82b..4fdc420256b 100644 --- a/tests/installation/test_installer.py +++ b/tests/installation/test_installer.py @@ -15,6 +15,7 @@ from poetry.repositories.installed_repository import InstalledRepository from poetry.utils._compat import PY2 from poetry.utils._compat import Path +from poetry.utils.env import MockEnv from poetry.utils.env import NullEnv from poetry.utils.toml_file import TomlFile from tests.helpers import get_dependency @@ -1461,15 +1462,15 @@ def test_update_multiple_times_with_split_dependencies_is_idempotent( package.python_versions = "~2.7 || ^3.4" package.add_dependency("A", "^1.0") - a = get_package("A", "1.0") - a.add_dependency("B", ">=1.0.1") - a.add_dependency("C", {"version": "^1.0", "python": "~2.7"}) - a.add_dependency("C", {"version": "^2.0", "python": "^3.4"}) + a10 = get_package("A", "1.0") + a11 = get_package("A", "1.1") + a11.add_dependency("B", ">=1.0.1") + a11.add_dependency("C", {"version": "^1.0", "python": "~2.7"}) + a11.add_dependency("C", {"version": "^2.0", "python": "^3.4"}) b101 = get_package("B", "1.0.1") - b101.python_versions = ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*" b110 = get_package("B", "1.1.0") - b110.python_versions = ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*" - repo.add_package(a) + repo.add_package(a10) + repo.add_package(a11) repo.add_package(b101) repo.add_package(b110) repo.add_package(get_package("C", "1.0")) @@ -1557,3 +1558,50 @@ def test_installer_uses_prereleases_if_they_are_compatible( installer.run() assert len(installer.installer.installs) == 2 + + +def test_installer_can_handle_old_lock_files( + installer, locker, package, repo, installed +): + pool = Pool() + pool.add_repository(MockRepository()) + + package.add_dependency("pytest", "^3.5", category="dev") + + locker.mock_lock_data(fixture("with-pypi-repository")) + + installer = Installer( + NullIO(), MockEnv(), package, locker, pool, installed=installed + ) + + installer.run() + + assert 6 == len(installer.installer.installs) + + installer = Installer( + NullIO(), + MockEnv(version_info=(2, 7, 18)), + package, + locker, + pool, + installed=installed, + ) + + installer.run() + + # funcsigs will be added + assert 7 == len(installer.installer.installs) + + installer = Installer( + NullIO(), + MockEnv(version_info=(2, 7, 18), platform="win32"), + package, + locker, + pool, + installed=installed, + ) + + installer.run() + + # colorama will be added + assert 8 == len(installer.installer.installs) diff --git a/tests/packages/test_locker.py b/tests/packages/test_locker.py index 1fe3ca1c48f..bf1daf0adb3 100644 --- a/tests/packages/test_locker.py +++ b/tests/packages/test_locker.py @@ -266,10 +266,7 @@ def test_extras_dependencies_are_ordered(locker, root): version = "1.0.0" [package.dependencies] -[package.dependencies.B] -extras = ["a", "b", "c"] -optional = true -version = "^1.0.0" +B = {version = "^1.0.0", extras = ["a", "b", "c"], optional = true} [metadata] content-hash = "115cf985d932e9bf5f540555bbdd75decbb62cac81e399375fc19f6277f8c1d8" diff --git a/tests/puzzle/test_solver.py b/tests/puzzle/test_solver.py index 9b99ac3def5..e9d32ba058d 100644 --- a/tests/puzzle/test_solver.py +++ b/tests/puzzle/test_solver.py @@ -559,21 +559,6 @@ def test_solver_sub_dependencies_with_requirements_complex(solver, repo, package ], ) - op = ops[3] # d - assert str(op.package.marker) == 'python_version < "4.0"' - - op = ops[0] # e - assert str(op.package.marker) == ( - 'python_version < "4.0" and sys_platform == "win32" ' - 'or python_version < "5.0" and sys_platform == "win32"' - ) - - op = ops[1] # f - assert str(op.package.marker) == 'python_version < "5.0"' - - op = ops[4] # a - assert str(op.package.marker) == 'python_version < "5.0"' - def test_solver_sub_dependencies_with_not_supported_python_version( solver, repo, package @@ -773,11 +758,6 @@ def test_solver_duplicate_dependencies_same_constraint(solver, repo, package): ], ) - op = ops[0] - assert ( - str(op.package.marker) == 'python_version == "2.7" or python_version >= "3.4"' - ) - def test_solver_duplicate_dependencies_different_constraints(solver, repo, package): package.add_dependency("A") @@ -804,12 +784,6 @@ def test_solver_duplicate_dependencies_different_constraints(solver, repo, packa ], ) - op = ops[0] - assert str(op.package.marker) == 'python_version < "3.4"' - - op = ops[1] - assert str(op.package.marker) == 'python_version >= "3.4"' - def test_solver_duplicate_dependencies_different_constraints_same_requirements( solver, repo, package @@ -872,12 +846,6 @@ def test_solver_duplicate_dependencies_sub_dependencies(solver, repo, package): ], ) - op = ops[2] - assert str(op.package.marker) == 'python_version < "3.4"' - - op = ops[3] - assert str(op.package.marker) == 'python_version >= "3.4"' - def test_solver_fails_if_dependency_name_does_not_match_package(solver, repo, package): package.add_dependency("my-demo", {"git": "https://github.com/demo/demo.git"}) @@ -1006,11 +974,6 @@ def test_solver_does_not_trigger_conflict_for_python_constraint_if_python_requir check_solver_result(ops, [{"job": "install", "package": package_a}]) - assert ( - str(ops[0].package.marker) - == 'python_version >= "3.6" and python_version < "4.0"' - ) - def test_solver_does_not_trigger_conflict_for_python_constraint_if_python_requirement_is_compatible_multiple( solver, repo, package @@ -1039,11 +1002,6 @@ def test_solver_does_not_trigger_conflict_for_python_constraint_if_python_requir ], ) - assert str(ops[0].package.marker) == ( - 'python_version >= "3.6" and python_version < "4.0" ' - 'or python_version >= "3.5.3" and python_version < "4.0.0"' - ) - def test_solver_triggers_conflict_for_dependency_python_not_fully_compatible_with_package_python( solver, repo, package @@ -1079,44 +1037,6 @@ def test_solver_finds_compatible_package_for_dependency_python_not_fully_compati check_solver_result(ops, [{"job": "install", "package": package_a100}]) - assert ( - str(ops[0].package.marker) - == 'python_version >= "3.5" and python_version < "4.0"' - ) - - -def test_solver_sets_appropriate_markers_when_solving(solver, repo, package): - dep = dependency_from_pep_508( - 'B (>=1.0); python_version >= "3.6" and sys_platform != "win32"' - ) - - package.add_dependency("A", "^1.0") - - package_a = get_package("A", "1.0.0") - package_a.requires.append(dep) - - package_b = get_package("B", "1.0.0") - - repo.add_package(package_a) - repo.add_package(package_b) - - ops = solver.solve() - - check_solver_result( - ops, - [ - {"job": "install", "package": package_b}, - {"job": "install", "package": package_a}, - ], - ) - - assert ( - str(ops[0].package.marker) - == 'python_version >= "3.6" and sys_platform != "win32"' - ) - - assert str(ops[1].package.marker) == "" - def test_solver_does_not_trigger_new_resolution_on_duplicate_dependencies_if_only_extras( solver, repo, package @@ -1902,31 +1822,6 @@ def test_ignore_python_constraint_no_overlap_dependencies(solver, repo, package) ) -def test_solver_properly_propagates_markers(solver, repo, package): - package.python_versions = "~2.7 || ^3.4" - package.add_dependency( - "A", - { - "version": "^1.0", - "markers": "python_version >= '3.6' and implementation_name != 'pypy'", - }, - ) - - package_a = get_package("A", "1.0.0") - package_a.python_versions = ">=3.6" - - repo.add_package(package_a) - - ops = solver.solve() - - check_solver_result(ops, [{"job": "install", "package": package_a}]) - - assert ( - str(ops[0].package.marker) - == 'python_version >= "3.6" and implementation_name != "pypy"' - ) - - def test_solver_should_not_go_into_an_infinite_loop_on_duplicate_dependencies( solver, repo, package ): @@ -1956,6 +1851,3 @@ def test_solver_should_not_go_into_an_infinite_loop_on_duplicate_dependencies( {"job": "install", "package": package_a}, ], ) - - assert 'implementation_name == "pypy"' == str(ops[0].package.marker) - assert 'implementation_name != "pypy"' == str(ops[1].package.marker)