diff --git a/piptools/sync.py b/piptools/sync.py index 579436a34..430b4bb6f 100644 --- a/piptools/sync.py +++ b/piptools/sync.py @@ -82,18 +82,19 @@ def merge(requirements, ignore_conflicts): # Limitation: URL requirements are merged by precise string match, so # "file:///example.zip#egg=example", "file:///example.zip", and # "example==1.0" will not merge with each other - key = key_from_ireq(ireq) - - if not ignore_conflicts: - existing_ireq = by_key.get(key) - if existing_ireq: - # NOTE: We check equality here since we can assume that the - # requirements are all pinned - if ireq.specifier != existing_ireq.specifier: - raise IncompatibleRequirements(ireq, existing_ireq) - - # TODO: Always pick the largest specifier in case of a conflict - by_key[key] = ireq + if ireq.match_markers(): + key = key_from_ireq(ireq) + + if not ignore_conflicts: + existing_ireq = by_key.get(key) + if existing_ireq: + # NOTE: We check equality here since we can assume that the + # requirements are all pinned + if ireq.specifier != existing_ireq.specifier: + raise IncompatibleRequirements(ireq, existing_ireq) + + # TODO: Always pick the largest specifier in case of a conflict + by_key[key] = ireq return by_key.values() diff --git a/tests/test_cli_sync.py b/tests/test_cli_sync.py index ffc21720c..3f4de5cfa 100644 --- a/tests/test_cli_sync.py +++ b/tests/test_cli_sync.py @@ -93,21 +93,34 @@ def test_force_files_with_dot_in_extension(runner): assert out.exit_code == 0 -def test_merge_error(runner): +@pytest.mark.parametrize( + ("req_lines", "should_raise"), + [ + (["six>1.10.0", "six<1.10.0"], True), + ( + ["six>1.10.0 ; python_version>='3.0'", "six<1.10.0 ; python_version<'3.0'"], + False, + ), + ], +) +def test_merge_error(req_lines, should_raise, runner): """ Sync command should raise an error if there are merge errors. + It should not raise an error if otherwise incompatible requirements + are isolated by exclusive environment markers. """ with open("requirements.txt", "w") as req_in: - req_in.write("six>1.10.0\n") - - # Add incompatible package - req_in.write("six<1.10.0") + for line in req_lines: + req_in.write(line + "\n") with mock.patch("piptools.sync.check_call"): out = runner.invoke(cli, ["-n"]) - assert out.exit_code == 2 - assert "Incompatible requirements found" in out.stderr + if should_raise: + assert out.exit_code == 2 + assert "Incompatible requirements found" in out.stderr + else: + assert out.exit_code == 0 @pytest.mark.parametrize(