Skip to content

Commit

Permalink
Finish support for editable constraints
Browse files Browse the repository at this point in the history
  • Loading branch information
sbidoul committed Sep 7, 2023
1 parent d76b4dd commit a9da47d
Show file tree
Hide file tree
Showing 3 changed files with 73 additions and 18 deletions.
58 changes: 41 additions & 17 deletions src/pip_deepfreeze/pip.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
from .utils import (
check_call,
check_output,
get_temp_path_in_dir,
log_debug,
log_info,
log_warning,
Expand Down Expand Up @@ -59,6 +60,7 @@ def pip_upgrade_project(
to install them (requirement already satisfied).
- Passing --upgrade to pip makes it too slow to my taste (need to check performance
with the new resolver).
- pip does not support editable contraints
In the meantime, here is our upgrade algorithm:
1. List installed dependencies of project (pip_freeze_dependencies).
Expand All @@ -71,16 +73,29 @@ def pip_upgrade_project(
update the version specifier in requirements.txt, and reinstalling the project with
this function.
"""
# 1. parse constraints
constraints_without_editables_filename = get_temp_path_in_dir(
dir=project_root, prefix="requirements.", suffix=".txt.df"
)
editable_constraints = []
constraint_reqs = {}
for req_line in parse_req_file(
str(constraints_filename), recurse=False, reqs_only=False
):
assert not isinstance(req_line, NestedRequirementsLine)
if isinstance(req_line, RequirementLine):
req_name = get_req_name(req_line.requirement)
assert req_name # XXX user error instead?
constraint_reqs[req_name] = normalize_req_line(req_line.requirement)
# 1. parse constraints, filter out editable constraints that pip does not support
with constraints_without_editables_filename.open(
mode="w", encoding="utf-8"
) as constraints_without_editables_file:
for req_line in parse_req_file(
str(constraints_filename), recurse=False, reqs_only=False
):
assert not isinstance(req_line, NestedRequirementsLine)
if isinstance(req_line, RequirementLine):
req_name = get_req_name(req_line.requirement)
assert req_name # XXX user error instead?
constraint_reqs[req_name] = normalize_req_line(req_line.requirement)
if not req_line.is_editable:
print(req_line.raw_line, file=constraints_without_editables_file)
else:
editable_constraints.extend(["-e", req_line.requirement])
else:
print(req_line.raw_line, file=constraints_without_editables_file)
# 2. get installed frozen dependencies of project
installed_reqs = {
get_req_name(req_line): normalize_req_line(req_line)
Expand All @@ -102,21 +117,30 @@ def pip_upgrade_project(
# 4. install project with constraints
project_name = get_project_name(python, project_root)
log_info(f"Installing/updating {project_name}")
cmd = [python, "-m", "pip", "install", "-c", f"{constraints_filename}"]
cmd = [
python,
"-m",
"pip",
"install",
"-c",
f"{constraints_without_editables_filename}",
*editable_constraints,
]
cmd.append("-e")
if extras:
extras_str = ",".join(extras)
cmd.append(f"{project_root}[{extras_str}]")
else:
cmd.append(f"{project_root}")
log_debug(f"Running {shlex.join(cmd)}")
with open(constraints_filename) as f:
constraints = f.read().strip()
if constraints:
log_debug(f"with {constraints_filename}:")
log_debug(constraints)
else:
log_debug(f"with empty {constraints_filename}.")
constraints = constraints_without_editables_filename.read_text(
encoding="utf-8"
).strip()
if constraints:
log_debug(f"with {constraints_without_editables_filename}:")
log_debug(constraints)
else:
log_debug(f"with empty {constraints_without_editables_filename}.")
check_call(cmd)


Expand Down
2 changes: 1 addition & 1 deletion src/pip_deepfreeze/req_merge.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ def prepare_frozen_reqs_for_upgrade(
if req_name in to_upgrade_set:
continue
frozen_reqs.add(req_name)
yield frozen_req.requirement
yield frozen_req.raw_line
# 3. emit in_reqs that have not been emitted as frozen reqs
for req_name, in_req in in_reqs:
if req_name not in frozen_reqs:
Expand Down
31 changes: 31 additions & 0 deletions tests/test_sync.py
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,37 @@ def test_sync_project_root(virtualenv_python, editable_foobar_path):
assert (editable_foobar_path / "requirements.txt").exists()


def test_sync_editable_dep(virtualenv_python, tmp_path):
pyproject_toml = tmp_path / "pyproject.toml"
pyproject_toml.write_text(
textwrap.dedent(
"""
[project]
name = "foobar"
version = "0.1"
dependencies = ["pip-test-package"]
"""
)
)
constraints = tmp_path / "requirements.txt.in"
constraints.write_text(
"-e git+https://github.com/PyPA/pip-test-package#egg=pip-test-package\n"
)
subprocess.check_call(
[sys.executable, "-m", "pip_deepfreeze", "--python", virtualenv_python, "sync"],
cwd=tmp_path,
)
requirements_path = tmp_path / "requirements.txt"
assert requirements_path.is_file()
assert "-e " in requirements_path.read_text(), requirements_path.read_text()
# test that a second run keeps editableness
subprocess.check_call(
[sys.executable, "-m", "pip_deepfreeze", "--python", virtualenv_python, "sync"],
cwd=tmp_path,
)
assert "-e " in requirements_path.read_text(), requirements_path.read_text()


def test_sync_uninstall(virtualenv_python, tmp_path, testpkgs):
setup_py = tmp_path / "setup.py"
setup_py.write_text(
Expand Down

0 comments on commit a9da47d

Please sign in to comment.