Skip to content

Commit

Permalink
Merge pull request #82 from sbidoul/constraints-txt
Browse files Browse the repository at this point in the history
Read constraints from `constraints.txt` and fallback to `requirements.txt.in`
  • Loading branch information
sbidoul authored Feb 23, 2024
2 parents cb1d070 + 95efd0e commit d1192df
Show file tree
Hide file tree
Showing 5 changed files with 42 additions and 23 deletions.
24 changes: 12 additions & 12 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ To update one or more dependencies to the latest allowed version, run:
If you need to add some dependencies from VCS references (e.g. when a library
with a patch you need is not available as a release on a package index), add
the dependency as usual in your project, then add the VCS reference to a file
named ``requirements.txt.in`` like this::
named ``constraints.txt`` like this::

DEPENDENCYNAME @ git+https://g.c/org/project@branch

Expand All @@ -129,7 +129,7 @@ reference pinned at the exact commit that was installed (you need pip version
the same branch, simply use ``pip-df sync --update DEPENDENCYNAME``.

When, later again, your branch is merged upstream and the project has published
a release, remove the line from ``requirements.txt.in`` and run ``pip-df sync
a release, remove the line from ``constraints.txt`` and run ``pip-df sync
--update DEPENDENCYNAME`` to update to the latest released version.

How to
Expand Down Expand Up @@ -173,11 +173,11 @@ Refreshing all pinned dependencies.
``pip-df sync --update-all``. This is equivalent to removing
``requirements.txt`` then running ``pip-df sync``. This is also roughly
equivalent to reinstalling in an empty virtualenv with ``pip install -e . -c
requirements.txt.in`` then running ``pip freeze > requirements.txt``.
constraints.txt`` then running ``pip freeze > requirements.txt``.

Using another package index than PyPI.

Create a file named ``requirements.txt.in`` in your project root, and add
Create a file named ``constraints.txt`` in your project root, and add
pip options to it, such as ``--extra-index-url`` or ``--find-links``. You
can add any option that `pip supports in requirements files
<https://pip.pypa.io/en/stable/reference/pip_install/#requirements-file-format>`_.
Expand All @@ -189,14 +189,14 @@ Installing dependencies from VCS.
it. Assume for instance your project depends on the ``packaging`` library
and you want to install a pull request you made to it. To do so, make sure
``packaging`` is declared as a regular dependency of your project. Then
add the VCS reference in ``requirements.txt.in`` like so::
add the VCS reference in ``constraints.txt`` like so::

packaging @ git+https://github.com/you/packaging@your-branch

Then run ``pip-df sync --update packaging`` to install from the branch and
pin the exact commit in ``requirements.txt`` for reproducibility. When
upstream merges your PR and cuts a release, you can simply remove the line
from ``requirements.txt.in`` and run ``pip-df sync --update packaging`` to
from ``constraints.txt`` and run ``pip-df sync --update packaging`` to
refresh to the latest released version.

Working with extras.
Expand All @@ -212,16 +212,16 @@ Working with extras.
FAQ
---

What should I put in ``requirements.txt.in``? Should I add all my dependencies
What should I put in ``constraints.txt``? Should I add all my dependencies
there?

``requirements.txt.in`` is optional. The dependencies of your project must be
``constraints.txt`` is optional. The dependencies of your project must be
declared primarily in ``pyproject.toml`` (or the legacy ``setup.py/setup.cfg``).
``requirements.txt.in`` may contain additional constraints if needed, such as version
``constraints.txt`` may contain additional constraints if needed, such as version
constraints on indirect dependencies that you don't control, or VCS links for
dependencies that you need to install from VCS source.

I have added a constraint in ``requirements.txt.in`` but ``pip-df sync`` does
I have added a constraint in ``constraints.txt`` but ``pip-df sync`` does
not honor it. What is going on?

``pip-df sync`` always gives priority to versions pinned in ``requirements.txt``,
Expand All @@ -243,7 +243,7 @@ not honor it. What is going on?
How can I pass options to pip?

The most reliable and repeatable way to pass options to pip is to add them
in ``requirements.txt.in``. The pip documentation lists `options that are
in ``constraints.txt``. The pip documentation lists `options that are
allowed in requirements files
<https://pip.pypa.io/en/stable/reference/pip_install/#requirements-file-format>`_.
Global options can also be set in the pip configuration file or passed via
Expand Down Expand Up @@ -321,7 +321,7 @@ pip-df sync
Install/reinstall the project. Install/update dependencies to the latest
allowed version according to pinned dependencies in requirements.txt or
constraints in requirements.txt.in. On demand update of dependencies to to
constraints in constraints.txt. On demand update of dependencies to to
the latest version that matches constraints. Optionally uninstall unneeded
dependencies.
Expand Down
2 changes: 2 additions & 0 deletions news/59.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Read constraints from ``constraints.txt`` first and fallback to ``requirements.txt.in``
as the former name better matches the purpose of the file.
2 changes: 1 addition & 1 deletion src/pip_deepfreeze/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ def sync(
Install/reinstall the project. Install/update dependencies to the
latest allowed version according to pinned dependencies in
requirements.txt or constraints in requirements.txt.in. On demand
requirements.txt or constraints in constraints.txt/requirements.txt.in. On demand
update of dependencies to to the latest version that matches
constraints. Optionally uninstall unneeded dependencies.
"""
Expand Down
21 changes: 19 additions & 2 deletions src/pip_deepfreeze/sync.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,22 @@ def _req_line_sort_key(req_line: str) -> str:
return req_name


def _constraints_path(project_root: Path) -> Path:
constraints_txt = project_root / "constraints.txt"
if not constraints_txt.is_file():
# fallback to requirements.txt.in if it exists, for backward compatibility
requirements_txt_in = project_root / "requirements.txt.in"
if requirements_txt_in.is_file():
log_debug(
"Reading constraints and pip options "
"from 'requirements.txt.in'. "
"Consider renaming it to 'constraints.txt' "
"as this name better describes the purpose of the file."
)
return requirements_txt_in
return constraints_txt


def sync(
python: str,
upgrade_all: bool,
Expand All @@ -48,7 +64,7 @@ def sync(
) -> None:
project_name = get_project_name(python, project_root)
project_name_with_extras = make_project_name_with_extras(project_name, extras)
constraints_path = project_root / "requirements.txt.in"
constraints_path = _constraints_path(project_root)
# upgrade project and its dependencies, if needed
merged_constraints_path = get_temp_path_in_dir(
dir=project_root, prefix="requirements.", suffix=".txt.df"
Expand Down Expand Up @@ -83,7 +99,8 @@ def sync(
print("# frozen requirements generated by pip-deepfreeze", file=f)
# output pip options in main requirements only
if not extra and constraints_path.exists():
# XXX can we avoid this second parse of requirements.txt.in?
# XXX can we avoid this second parse of
# constraints.txt/requirements.txt.in?
for parsed_req_line in parse_req_file(
str(constraints_path),
reqs_only=False,
Expand Down
16 changes: 8 additions & 8 deletions tests/test_sync.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@


def test_sync(virtualenv_python, testpkgs, tmp_path):
(tmp_path / "requirements.txt.in").write_text(
(tmp_path / "constraints.txt").write_text(
textwrap.dedent(
f"""\
--pre
Expand Down Expand Up @@ -48,7 +48,7 @@ def test_sync(virtualenv_python, testpkgs, tmp_path):


def test_sync_normalization(virtualenv_python, testpkgs, tmp_path):
(tmp_path / "requirements.txt.in").write_text(
(tmp_path / "constraints.txt").write_text(
textwrap.dedent(
f"""\
--no-index
Expand Down Expand Up @@ -158,7 +158,7 @@ def test_sync_editable_dep(virtualenv_python, tmp_path):
"""
)
)
constraints = tmp_path / "requirements.txt.in"
constraints = tmp_path / "constraints.txt"
constraints.write_text(
"-e git+https://github.com/PyPA/pip-test-package#egg=pip-test-package\n"
)
Expand Down Expand Up @@ -189,7 +189,7 @@ def test_sync_uninstall(virtualenv_python, tmp_path, testpkgs):
)
)
(tmp_path / "setup.cfg").write_text("[metadata]\nname = foobar\n") # for perf
in_reqs = tmp_path / "requirements.txt.in"
in_reqs = tmp_path / "constraints.txt"
in_reqs.write_text(f"--no-index\n-f {testpkgs}")
sync(
virtualenv_python,
Expand Down Expand Up @@ -261,7 +261,7 @@ def test_sync_update_new_dep(virtualenv_python, testpkgs, tmp_path):
)
)
(tmp_path / "setup.cfg").write_text("[metadata]\nname = theproject\n") # for perf
(tmp_path / "requirements.txt.in").write_text(
(tmp_path / "constraints.txt").write_text(
textwrap.dedent(
f"""\
--no-index
Expand Down Expand Up @@ -309,7 +309,7 @@ def test_sync_update_all_new_dep(virtualenv_python, testpkgs, tmp_path):
)
)
(tmp_path / "setup.cfg").write_text("[metadata]\nname = theproject\n") # for perf
(tmp_path / "requirements.txt.in").write_text(
(tmp_path / "constraints.txt").write_text(
textwrap.dedent(
f"""\
--no-index
Expand Down Expand Up @@ -344,7 +344,7 @@ def test_sync_extras(virtualenv_python, testpkgs, tmp_path):
)
)
(tmp_path / "setup.cfg").write_text("[metadata]\nname = theproject\n") # for perf
(tmp_path / "requirements.txt.in").write_text(
(tmp_path / "constraints.txt").write_text(
textwrap.dedent(
f"""\
--no-index
Expand Down Expand Up @@ -389,7 +389,7 @@ def test_sync_extras(virtualenv_python, testpkgs, tmp_path):


def test_post_sync_command(virtualenv_python, testpkgs, tmp_path):
(tmp_path / "requirements.txt.in").write_text(
(tmp_path / "constraints.txt").write_text(
textwrap.dedent(
f"""\
--no-index
Expand Down

0 comments on commit d1192df

Please sign in to comment.