Skip to content

Commit

Permalink
Merge pull request #471 from derek-miller/exclude-pip-constraints
Browse files Browse the repository at this point in the history
pip-compile includes irrelevant constraints from pip contraints file
  • Loading branch information
davidovich authored Mar 31, 2017
2 parents 99f6c82 + 5bf5b97 commit 62d85ea
Show file tree
Hide file tree
Showing 8 changed files with 33 additions and 14 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

- Added a `--max-rounds` argument to the pip-compile command to allow for solving large requirement sets ([#472](https://github.com/jazzband/pip-tools/pull/472))
- Exclude unsafe packages' dependencies when `--allow-unsafe` is not in use (#445)
- Exclude irrelevant pip constraints ([#471](https://github.com/jazzband/pip-tools/pull/471))

# 1.8.2

Expand Down
2 changes: 1 addition & 1 deletion piptools/repositories/local.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ def find_best_match(self, ireq, prereleases=None):
if existing_pin and ireq_satisfied_by_existing_pin(ireq, existing_pin):
project, version, _ = as_tuple(existing_pin)
return make_install_requirement(
project, version, ireq.extras
project, version, ireq.extras, constraint=ireq.constraint
)
else:
return self.repository.find_best_match(ireq, prereleases)
Expand Down
2 changes: 1 addition & 1 deletion piptools/repositories/pypi.py
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ def find_best_match(self, ireq, prereleases=None):

# Turn the candidate into a pinned InstallRequirement
return make_install_requirement(
best_candidate.project, best_candidate.version, ireq.extras
best_candidate.project, best_candidate.version, ireq.extras, constraint=ireq.constraint
)

def get_dependencies(self, ireq):
Expand Down
14 changes: 9 additions & 5 deletions piptools/resolver.py
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,8 @@ def resolve(self, max_rounds=10):
self.dependency_cache.clear()
self.repository.clear_caches()

self._check_constraints()
self.check_constraints(chain(self.our_constraints,
self.their_constraints))

# Ignore existing packages
os.environ[str('PIP_EXISTS_ACTION')] = str('i') # NOTE: str() wrapping necessary for Python 2/3 compat
Expand Down Expand Up @@ -118,10 +119,12 @@ def resolve(self, max_rounds=10):
self.repository.freshen_build_caches()

del os.environ['PIP_EXISTS_ACTION']
return best_matches
# Only include hard requirements and not pip constraints
return {req for req in best_matches if not req.constraint}

def _check_constraints(self):
for constraint in chain(self.our_constraints, self.their_constraints):
@staticmethod
def check_constraints(constraints):
for constraint in constraints:
if constraint.link is not None and not constraint.editable:
msg = ('pip-compile does not support URLs as packages, unless they are editable. '
'Perhaps add -e option?')
Expand Down Expand Up @@ -157,6 +160,7 @@ def _group_constraints(self, constraints):
for ireq in ireqs:
# NOTE we may be losing some info on dropped reqs here
combined_ireq.req.specifier &= ireq.req.specifier
combined_ireq.constraint &= ireq.constraint
# Return a sorted, de-duped tuple of extras
combined_ireq.extras = tuple(sorted(set(tuple(combined_ireq.extras) + tuple(ireq.extras))))
yield combined_ireq
Expand Down Expand Up @@ -275,7 +279,7 @@ def _iter_dependencies(self, ireq):
log.debug(' {:25} requires {}'.format(format_requirement(ireq),
', '.join(sorted(dependency_strings, key=lambda s: s.lower())) or '-'))
for dependency_string in dependency_strings:
yield InstallRequirement.from_line(dependency_string)
yield InstallRequirement.from_line(dependency_string, constraint=ireq.constraint)

def reverse_dependencies(self, ireqs):
non_editable = [ireq for ireq in ireqs if not ireq.editable]
Expand Down
8 changes: 7 additions & 1 deletion piptools/scripts/compile.py
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,12 @@ 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))

# Check the given base set of constraints first
Resolver.check_constraints(constraints)

# The requirement objects are modified in-place so we need to save off the list of primary packages first
primary_packages = {key_from_req(ireq.req) for ireq in constraints if not ireq.constraint}

try:
resolver = Resolver(constraints, repository, prereleases=pre,
clear_caches=rebuild, allow_unsafe=allow_unsafe)
Expand Down Expand Up @@ -230,7 +236,7 @@ def cli(verbose, dry_run, pre, rebuild, find_links, index_url, extra_index_url,
format_control=repository.finder.format_control)
writer.write(results=results,
reverse_dependencies=reverse_dependencies,
primary_packages={key_from_req(ireq.req) for ireq in constraints},
primary_packages=primary_packages,
markers={key_from_req(ireq.req): ireq.markers
for ireq in constraints if ireq.markers},
hashes=hashes)
Expand Down
4 changes: 2 additions & 2 deletions piptools/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,14 +51,14 @@ def comment(text):
return style(text, fg='green')


def make_install_requirement(name, version, extras):
def make_install_requirement(name, version, extras, constraint=False):
# If no extras are specified, the extras string is blank
extras_string = ""
if extras:
# Sort extras for stability
extras_string = "[{}]".format(",".join(sorted(extras)))

return InstallRequirement.from_line('{}{}=={}'.format(name, extras_string, str(version)))
return InstallRequirement.from_line('{}{}=={}'.format(name, extras_string, str(version)), constraint=constraint)


def format_requirement(ireq, marker=None):
Expand Down
4 changes: 2 additions & 2 deletions tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ def find_best_match(self, ireq, prereleases=False):
if not versions:
raise NoCandidateFound(ireq, self.index[key_from_req(ireq.req)])
best_version = max(versions, key=Version)
return make_install_requirement(key_from_req(ireq.req), best_version, ireq.extras)
return make_install_requirement(key_from_req(ireq.req), best_version, ireq.extras, constraint=ireq.constraint)

def get_dependencies(self, ireq):
if ireq.editable:
Expand All @@ -47,7 +47,7 @@ def get_dependencies(self, ireq):
# Store non-extra dependencies under the empty string
extras += ("",)
dependencies = [dep for extra in extras for dep in self.index[name][version][extra]]
return [InstallRequirement.from_line(dep) for dep in dependencies]
return [InstallRequirement.from_line(dep, constraint=ireq.constraint) for dep in dependencies]


class FakeInstalledDistribution(object):
Expand Down
12 changes: 10 additions & 2 deletions tests/test_resolver.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
(['Flask'],
['flask==0.10.1', 'itsdangerous==0.24', 'markupsafe==0.23',
'jinja2==2.7.3', 'werkzeug==0.10.4']),
'jinja2==2.7.3', 'werkzeug==0.10.4']),
(['Jinja2', 'markupsafe'],
['jinja2==2.7.3', 'markupsafe==0.23']),
Expand Down Expand Up @@ -98,10 +98,18 @@
# Exclude package dependcy of setuptools as it is unsafe.
(['html5lib'], ['html5lib==0.999999999']),
# We shouldn't include irrelevant pip constraints
# See: GH-471
(['Flask', ('click', True), ('itsdangerous', True)],
['flask==0.10.1', 'itsdangerous==0.24', 'markupsafe==0.23',
'jinja2==2.7.3', 'werkzeug==0.10.4']
),
])
)
def test_resolver(resolver, from_line, input, expected, prereleases):
input = [from_line(line) for line in input]
input = [line if isinstance(line, tuple) else (line, False) for line in input]
input = [from_line(req[0], constraint=req[1]) for req in input]
output = resolver(input, prereleases=prereleases).resolve()
output = {str(line) for line in output}
assert output == {str(line) for line in expected}

0 comments on commit 62d85ea

Please sign in to comment.