Skip to content

Commit

Permalink
Merge branch 'master' into dstufft-generate-hashes
Browse files Browse the repository at this point in the history
  • Loading branch information
nvie committed Nov 17, 2016
2 parents 9996891 + d14829c commit abe2b48
Show file tree
Hide file tree
Showing 6 changed files with 53 additions and 10 deletions.
9 changes: 9 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,12 @@
# 1.8.0

- Adds support for upgrading individual packages with a new option
`--upgrade-package`. To upgrade a _specific_ package to the latest or
a specific version use `--upgrade-package <pkg>`. To upgrade all packages,
you can still use `pip-compile --upgrade`. (#409)
- Improve support for extras, like `hypothesis[django]`


# 1.7.1

- Add `--allow-unsafe` option (#377)
Expand Down
11 changes: 10 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,17 @@ werkzeug==0.10.4 # via flask

And it will produce your `requirements.txt`, with all the Flask dependencies
(and all underlying dependencies) pinned. Put this file under version control
as well and periodically re-run `pip-compile --upgrade` to update the packages.
as well.

To update all packages, periodically re-run `pip-compile --upgrade`.

To update a specific package to the latest or a specific version use the `--upgrade-package` or `-P` flag:

```console
$ 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==2.0.0 # update the flask package to the latest, and requests to v2.0.0
```

Example usage for `pip-sync`
============================
Expand Down
1 change: 1 addition & 0 deletions examples/hypothesis.in
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
hypothesis[django]
7 changes: 5 additions & 2 deletions piptools/repositories/local.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
from __future__ import (absolute_import, division, print_function,
unicode_literals)

from piptools.utils import key_from_req
from piptools.utils import as_tuple, key_from_req, make_install_requirement
from .base import BaseRepository


Expand Down Expand Up @@ -57,7 +57,10 @@ def find_best_match(self, ireq, prereleases=None):
key = key_from_req(ireq.req)
existing_pin = self.existing_pins.get(key)
if existing_pin and ireq_satisfied_by_existing_pin(ireq, existing_pin):
return existing_pin
project, version, _ = as_tuple(existing_pin)
return make_install_requirement(
project, version, ireq.extras
)
else:
return self.repository.find_best_match(ireq, prereleases)

Expand Down
34 changes: 27 additions & 7 deletions piptools/scripts/compile.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,15 @@
import tempfile

import pip
from pip.req import parse_requirements
from pip.req import InstallRequirement, parse_requirements

from .. import click
from ..exceptions import PipToolsError
from ..logging import log
from ..repositories import LocalRequirementsRepository, PyPIRepository
from ..resolver import Resolver
from ..utils import (assert_compatible_pip_version, is_pinned_requirement,
key_from_req, name_from_req)
key_from_req)
from ..writer import OutputWriter

# Make sure we're using a compatible version of pip
Expand Down Expand Up @@ -50,6 +50,8 @@ class PipCommand(pip.basecommand.Command):
help="Annotate results, indicating where dependencies come from")
@click.option('-U', '--upgrade', is_flag=True, default=False,
help='Try to upgrade all dependencies to their latest versions')
@click.option('-P', '--upgrade-package', 'upgrade_packages', nargs=1, multiple=True,
help="Specify particular packages to upgrade.")
@click.option('-o', '--output-file', nargs=1, type=str, default=None,
help=('Output file name. Required if more than one input file is given. '
'Will be derived from input file otherwise.'))
Expand All @@ -59,7 +61,7 @@ class PipCommand(pip.basecommand.Command):
help="Generate pip 8 style hashes in the resulting requirements file.")
@click.argument('src_files', nargs=-1, type=click.Path(exists=True, allow_dash=True))
def cli(verbose, dry_run, pre, rebuild, find_links, index_url, extra_index_url,
client_cert, trusted_host, header, index, annotate, upgrade,
client_cert, trusted_host, header, index, annotate, upgrade, upgrade_packages,
output_file, allow_unsafe, generate_hashes, src_files):
"""Compiles requirements.txt from requirements.in specs."""
log.verbose = verbose
Expand All @@ -83,6 +85,9 @@ def cli(verbose, dry_run, pre, rebuild, find_links, index_url, extra_index_url,
base_name, _, _ = src_files[0].rpartition('.')
dst_file = base_name + '.txt'

if upgrade and upgrade_packages:
raise click.BadParameter('Only one of --upgrade or --upgrade-package can be provided as an argument.')

###
# Setup
###
Expand Down Expand Up @@ -120,14 +125,29 @@ 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)

# Pre-parse the inline package upgrade specs: they should take precedence
# over the stuff in the requirements files
upgrade_packages = [InstallRequirement.from_line(pkg)
for pkg in upgrade_packages]
upgrade_pkgs_by_key = {key_from_req(ireq.req): ireq
for ireq in upgrade_packages}

# Proxy with a LocalRequirementsRepository if --upgrade is not specified
# (= default invocation)
if not upgrade and os.path.exists(dst_file):
existing_pins = dict()
if not (upgrade or upgrade_packages) and os.path.exists(dst_file):
existing_pins = {}
ireqs = parse_requirements(dst_file, finder=repository.finder, session=repository.session, options=pip_options)
for ireq in ireqs:
key = key_from_req(ireq.req)

# Packages explicitly listed on the command line should not remain
# pinned by whatever is in the dst_file (the command line argument
# overwrites the current pins)
if key in upgrade_pkgs_by_key:
ireq = upgrade_pkgs_by_key[key]

if is_pinned_requirement(ireq):
existing_pins[name_from_req(ireq.req).lower()] = ireq
existing_pins[key] = ireq
repository = LocalRequirementsRepository(existing_pins, repository)

log.debug('Using indexes:')
Expand All @@ -150,7 +170,7 @@ def cli(verbose, dry_run, pre, rebuild, find_links, index_url, extra_index_url,
# pip requires filenames and not files. Since we want to support
# piping from stdin, we need to briefly save the input from stdin
# to a temporary file and have pip read that.
with tempfile.NamedTemporaryFile() as tmpfile:
with tempfile.NamedTemporaryFile(mode='wt') as tmpfile:
tmpfile.write(sys.stdin.read())
tmpfile.flush()
constraints.extend(parse_requirements(
Expand Down
1 change: 1 addition & 0 deletions piptools/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ def safeint(s):
except ValueError:
return 0


pip_version_info = tuple(safeint(digit) for digit in pip.__version__.split('.'))


Expand Down

0 comments on commit abe2b48

Please sign in to comment.