Skip to content

Commit

Permalink
Merge pull request #694 from richafrank/upgrade_packages-version
Browse files Browse the repository at this point in the history
Apply version constraints specified with package upgrade option
  • Loading branch information
vphilippon authored Nov 22, 2018
2 parents d182b50 + bc1d8b8 commit c1b4c67
Show file tree
Hide file tree
Showing 6 changed files with 51 additions and 9 deletions.
2 changes: 1 addition & 1 deletion README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,7 @@ To update a specific package to the latest or a specific version use the
$ pip-compile --upgrade-package flask # only update the flask package
$ pip-compile --upgrade-package flask --upgrade-package requests # update both the flask and requests packages
$ pip-compile -P flask -P requests # same as above, but shorter
$ pip-compile -P flask -P requests==2.0.0 # update the flask package to the latest, and requests to v2.0.0
If you use multiple Python versions, you can run ``pip-compile`` as
``py -X.Y -m piptools compile ...`` on Windows and
Expand Down
9 changes: 7 additions & 2 deletions piptools/scripts/compile.py
Original file line number Diff line number Diff line change
Expand Up @@ -129,15 +129,18 @@ def cli(verbose, dry_run, pre, rebuild, find_links, index_url, extra_index_url,
session = pip_command._build_session(pip_options)
repository = PyPIRepository(pip_options, session)

upgrade_install_reqs = {}
# Proxy with a LocalRequirementsRepository if --upgrade is not specified
# (= default invocation)
if not upgrade and os.path.exists(dst_file):
ireqs = parse_requirements(dst_file, finder=repository.finder, session=repository.session, options=pip_options)
# Exclude packages from --upgrade-package/-P from the existing pins: We want to upgrade.
upgrade_pkgs_key = {key_from_req(install_req_from_line(pkg).req) for pkg in upgrade_packages}
upgrade_reqs_gen = (install_req_from_line(pkg) for pkg in upgrade_packages)
upgrade_install_reqs = {key_from_req(install_req.req): install_req for install_req in upgrade_reqs_gen}

existing_pins = {key_from_req(ireq.req): ireq
for ireq in ireqs
if is_pinned_requirement(ireq) and key_from_req(ireq.req) not in upgrade_pkgs_key}
if is_pinned_requirement(ireq) and key_from_req(ireq.req) not in upgrade_install_reqs}
repository = LocalRequirementsRepository(existing_pins, repository)

log.debug('Using indexes:')
Expand Down Expand Up @@ -178,6 +181,8 @@ def cli(verbose, dry_run, pre, rebuild, find_links, index_url, extra_index_url,
constraints.extend(parse_requirements(
src_file, finder=repository.finder, session=repository.session, options=pip_options))

constraints.extend(upgrade_install_reqs.values())

# Filter out pip environment markers which do not match (PEP496)
constraints = [req for req in constraints
if req.markers is None or req.markers.evaluate()]
Expand Down
33 changes: 31 additions & 2 deletions tests/test_cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@
from click.testing import CliRunner

import pytest

from piptools.repositories import PyPIRepository
from piptools.scripts.compile import cli
from piptools.scripts.sync import cli as sync_cli
from pip._vendor.packaging.version import parse as parse_version
Expand Down Expand Up @@ -324,7 +326,29 @@ def test_upgrade_packages_option(tmpdir):
req_in.write('small-fake-a==0.1\nsmall-fake-b==0.1')

out = runner.invoke(cli, [
'-P', 'small_fake_b',
'-P', 'small-fake-b',
'-f', fake_package_dir,
])

assert out.exit_code == 0
assert 'small-fake-a==0.1' in out.output
assert 'small-fake-b==0.3' in out.output


def test_upgrade_packages_version_option(tmpdir):
"""
piptools respects --upgrade-package/-P inline list with specified versions.
"""
fake_package_dir = os.path.join(os.path.split(__file__)[0], 'test_data', 'minimal_wheels')
runner = CliRunner()
with runner.isolated_filesystem():
with open('requirements.in', 'w') as req_in:
req_in.write('small-fake-a\nsmall-fake-b')
with open('requirements.txt', 'w') as req_in:
req_in.write('small-fake-a==0.1\nsmall-fake-b==0.1')

out = runner.invoke(cli, [
'-P', 'small-fake-b==0.2',
'-f', fake_package_dir,
])

Expand All @@ -342,7 +366,12 @@ def test_generate_hashes_with_editable():
with open('requirements.in', 'w') as fp:
fp.write('-e {}\n'.format(small_fake_package_url))
fp.write('pytz==2017.2\n')
out = runner.invoke(cli, ['--generate-hashes'])
out = runner.invoke(
cli, [
'--generate-hashes',
'--index-url', PyPIRepository.DEFAULT_INDEX_URL,
],
)
expected = (
'#\n'
'# This file is autogenerated by pip-compile\n'
Expand Down
Binary file not shown.
4 changes: 3 additions & 1 deletion tests/test_repository_local.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,9 @@

def test_get_hashes_local_repository_cache_miss(from_line):
pip_command = get_pip_command()
pip_options, _ = pip_command.parse_args([])
pip_options, _ = pip_command.parse_args([
'--index-url', PyPIRepository.DEFAULT_INDEX_URL
])
session = pip_command._build_session(pip_options)
repository = PyPIRepository(pip_options, session)

Expand Down
12 changes: 9 additions & 3 deletions tests/test_repository_pypi.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,9 @@ def test_generate_hashes_all_platforms(from_line):
}

pip_command = get_pip_command()
pip_options, _ = pip_command.parse_args([])
pip_options, _ = pip_command.parse_args([
'--index-url', PyPIRepository.DEFAULT_INDEX_URL
])
session = pip_command._build_session(pip_options)
repository = PyPIRepository(pip_options, session)
ireq = from_line('cffi==1.9.1')
Expand All @@ -58,7 +60,9 @@ def test_generate_hashes_all_platforms(from_line):

def test_generate_hashes_without_interfering_with_each_other(from_line):
pip_command = get_pip_command()
pip_options, _ = pip_command.parse_args([])
pip_options, _ = pip_command.parse_args([
'--index-url', PyPIRepository.DEFAULT_INDEX_URL
])
session = pip_command._build_session(pip_options)
repository = PyPIRepository(pip_options, session)
repository.get_hashes(from_line('cffi==1.9.1'))
Expand All @@ -67,7 +71,9 @@ def test_generate_hashes_without_interfering_with_each_other(from_line):

def test_get_hashes_editable_empty_set(from_editable):
pip_command = get_pip_command()
pip_options, _ = pip_command.parse_args([])
pip_options, _ = pip_command.parse_args([
'--index-url', PyPIRepository.DEFAULT_INDEX_URL
])
session = pip_command._build_session(pip_options)
repository = PyPIRepository(pip_options, session)
ireq = from_editable('git+https://github.com/django/django.git#egg=django')
Expand Down

0 comments on commit c1b4c67

Please sign in to comment.