|
| 1 | +from pip.log import logger |
| 2 | +from pip.basecommand import Command |
| 3 | +from pip.util import get_installed_distributions |
| 4 | + |
| 5 | + |
| 6 | +class CheckCommand(Command): |
| 7 | + """Verify installed packages have compatible dependencies.""" |
| 8 | + name = 'check' |
| 9 | + usage = """ |
| 10 | + %prog [options]""" |
| 11 | + summary = 'Verify installed packages have compatible dependencies.' |
| 12 | + |
| 13 | + def setup_logging(self): |
| 14 | + logger.move_stdout_to_stderr() |
| 15 | + |
| 16 | + def run(self, options, args): |
| 17 | + all_requirements_met = True |
| 18 | + |
| 19 | + installed = get_installed_distributions() |
| 20 | + for dist in installed: |
| 21 | + |
| 22 | + missing_requirements = self.get_missing_requirements(dist, installed) |
| 23 | + for requirement in missing_requirements: |
| 24 | + logger.notify("%s %s requires %s, which is not installed." % |
| 25 | + (dist.project_name, dist.version, requirement.project_name)) |
| 26 | + |
| 27 | + incompatible_requirements = self.get_incompatible_requirements(dist, installed) |
| 28 | + for requirement, actual in incompatible_requirements: |
| 29 | + logger.notify("%s %s has requirement %s, but you have %s %s." % |
| 30 | + (dist.project_name, dist.version, requirement, |
| 31 | + actual.project_name, actual.version)) |
| 32 | + |
| 33 | + if missing_requirements or incompatible_requirements: |
| 34 | + all_requirements_met = False |
| 35 | + |
| 36 | + if not all_requirements_met: |
| 37 | + return 1 |
| 38 | + |
| 39 | + def get_missing_requirements(self, dist, installed_dists): |
| 40 | + """Return all of the requirements of `dist` that aren't present in |
| 41 | + `installed_dists`. |
| 42 | +
|
| 43 | + """ |
| 44 | + installed_names = set(d.project_name for d in installed_dists) |
| 45 | + |
| 46 | + missing_requirements = set() |
| 47 | + for requirement in dist.requires(): |
| 48 | + if requirement.project_name not in installed_names: |
| 49 | + missing_requirements.add(requirement) |
| 50 | + yield requirement |
| 51 | + |
| 52 | + def get_incompatible_requirements(self, dist, installed_dists): |
| 53 | + """Return all of the requirements of `dist` that are present in |
| 54 | + `installed_dists`, but have incompatible versions. |
| 55 | +
|
| 56 | + """ |
| 57 | + installed_dists_by_name = {} |
| 58 | + for installed_dist in installed_dists: |
| 59 | + installed_dists_by_name[installed_dist.project_name] = installed_dist |
| 60 | + |
| 61 | + incompatible_requirements = set() |
| 62 | + for requirement in dist.requires(): |
| 63 | + present_dist = installed_dists_by_name.get(requirement.project_name) |
| 64 | + |
| 65 | + if present_dist and present_dist not in requirement: |
| 66 | + incompatible_requirements.add((requirement, present_dist)) |
| 67 | + yield (requirement, present_dist) |
0 commit comments