Skip to content
Merged
Show file tree
Hide file tree
Changes from 9 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions docs/changelog/1140.bugfix.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
Pass ``--dependency-constraints-txt`` files through to the installer unmodified instead of re-parsing them into a
deduplicated set of lines, fixing a case where a hashed requirement (e.g. from ``pip-compile --generate-hashes``) could
have its ``--hash`` continuation line separated from its requirement line and silently dropped, depending on the
interpreter's hash seed - by :user:`manfred-kaiser`
8 changes: 7 additions & 1 deletion src/build/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -224,7 +224,13 @@ def _bootstrap_build_env(
install = env.install
if dependency_constraints_txt:
with open(dependency_constraints_txt, encoding='utf-8') as dependency_constraints_file:
install = partial(install, constraints=set(map(str.strip, dependency_constraints_file)))
constraints_text = dependency_constraints_file.read()
Comment thread
gaborbernat marked this conversation as resolved.
if constraints_text.strip():
# Passed through as a single element so the installer backends' `'\n'.join(constraints)` reproduces
Comment thread
gaborbernat marked this conversation as resolved.
Outdated
# the file byte-for-byte, instead of re-parsing it into individual lines (which can split a
# requirement from its `--hash` continuation lines, e.g. from `pip-compile --generate-hashes`,
# and silently drop the hash check).
install = partial(install, constraints=(constraints_text,))
Comment thread
gaborbernat marked this conversation as resolved.

# first install the build dependencies
install(builder.build_system_requires, _fresh=True)
Expand Down
39 changes: 38 additions & 1 deletion tests/test_main.py
Original file line number Diff line number Diff line change
Expand Up @@ -457,7 +457,44 @@ def test_build_package_with_constraints(
with pytest.raises(build.BuildBackendException, match=re.escape("Backend 'flit_core.buildapi' is not available.")):
build.__main__.build_package(package_test_flit, tmp_path, ['wheel'], dependency_constraints_txt=constraints_txt_path)

install.assert_any_call({'flit_core >=2,<4'}, constraints={'flit-core==12.34', 'foo==wot'}, _fresh=True)
install.assert_any_call({'flit_core >=2,<4'}, constraints=('flit-core==12.34\nfoo==wot\n',), _fresh=True)


@pytest.mark.isolated
def test_build_package_with_constraints_passes_file_through_unmodified(
mocker: pytest_mock.MockerFixture, tmp_path: pathlib.Path, package_test_flit: str
) -> None:
# As produced by e.g. `pip-compile --generate-hashes`: a requirement and its --hash options wrapped onto
# continuation lines. Regression test for the requirement/hash pair being split apart when re-parsed into
# individual lines - the file content must reach the installer byte-for-byte instead.
install = mocker.patch('build.env.DefaultIsolatedEnv.install')

constraints_text = (
'flit-core==12.34 \\\n --hash=sha256:aaaa \\\n --hash=sha256:bbbb\n # via test\nfoo==wot \\\n'
' --hash=sha256:cccc\n'
)
constraints_txt_path = tmp_path.joinpath('constraints.txt')
constraints_txt_path.write_text(constraints_text, encoding='utf-8')

with pytest.raises(build.BuildBackendException, match=re.escape("Backend 'flit_core.buildapi' is not available.")):
build.__main__.build_package(package_test_flit, tmp_path, ['wheel'], dependency_constraints_txt=constraints_txt_path)

install.assert_any_call({'flit_core >=2,<4'}, constraints=(constraints_text,), _fresh=True)


@pytest.mark.isolated
def test_build_package_with_empty_constraints_txt(
mocker: pytest_mock.MockerFixture, tmp_path: pathlib.Path, package_test_flit: str
) -> None:
install = mocker.patch('build.env.DefaultIsolatedEnv.install')

constraints_txt_path = tmp_path.joinpath('constraints.txt')
constraints_txt_path.write_text(' \n\n', encoding='utf-8')

with pytest.raises(build.BuildBackendException, match=re.escape("Backend 'flit_core.buildapi' is not available.")):
build.__main__.build_package(package_test_flit, tmp_path, ['wheel'], dependency_constraints_txt=constraints_txt_path)

install.assert_any_call({'flit_core >=2,<4'}, _fresh=True)


@pytest.mark.pypy3323bug
Expand Down
Loading