def populate_requirement_set(requirement_set, args, options, finder, session, name, wheel_cache): """ Marshal cmd line args into a requirement set. """ for filename in options.constraints: for req in parse_requirements(filename, constraint=True, finder=finder, options=options, session=session, wheel_cache=wheel_cache): requirement_set.add_requirement(req) for req in args: requirement_set.add_requirement( InstallRequirement.from_line(req, None, isolated=options.isolated_mode, wheel_cache=wheel_cache)) for req in options.editables: requirement_set.add_requirement( InstallRequirement.from_editable( req, default_vcs=options.default_vcs, isolated=options.isolated_mode, wheel_cache=wheel_cache)) found_req_in_file = False for filename in options.requirements: for req in parse_requirements(filename, finder=finder, options=options, session=session, wheel_cache=wheel_cache): found_req_in_file = True requirement_set.add_requirement(req) # If --require-hashes was a line in a requirements file, tell # RequirementSet about it: requirement_set.require_hashes = options.require_hashes if not (args or options.editables or found_req_in_file): opts = {'name': name} if options.find_links: msg = ('You must give at least one requirement to ' '%(name)s (maybe you meant "pip %(name)s ' '%(links)s"?)' % dict(opts, links=' '.join(options.find_links))) else: msg = ('You must give at least one requirement ' 'to %(name)s (see "pip help %(name)s")' % opts) logger.warning(msg)
def run(self, options, args): with self._build_session(options) as session: format_control = pip9.index.FormatControl(set(), set()) wheel_cache = WheelCache(options.cache_dir, format_control) requirement_set = RequirementSet( build_dir=None, src_dir=None, download_dir=None, isolated=options.isolated_mode, session=session, wheel_cache=wheel_cache, ) for name in args: requirement_set.add_requirement( InstallRequirement.from_line( name, isolated=options.isolated_mode, wheel_cache=wheel_cache ) ) for filename in options.requirements: for req in parse_requirements( filename, options=options, session=session, wheel_cache=wheel_cache): requirement_set.add_requirement(req) if not requirement_set.has_requirements: raise InstallationError( 'You must give at least one requirement to %(name)s (see ' '"pip help %(name)s")' % dict(name=self.name) ) requirement_set.uninstall(auto_confirm=options.yes)
def actually_resolve_reps(deps, index_lookup, markers_lookup, project, sources, verbose, clear, pre): from pip9 import basecommand, req from pip9._vendor import requests as pip_requests class PipCommand(basecommand.Command): """Needed for pip-tools.""" name = 'PipCommand' constraints = [] req_dir = tempfile.mkdtemp(prefix='pipenv-', suffix='-requirements') for dep in deps: if dep: if dep.startswith('-e '): constraint = req.InstallRequirement.from_editable( dep[len('-e '):]) else: fd, t = tempfile.mkstemp(prefix='pipenv-', suffix='-requirement.txt', dir=req_dir) with os.fdopen(fd, 'w') as f: f.write(dep) constraint = [ c for c in req.parse_requirements(t, session=pip_requests) ][0] # extra_constraints = [] if ' -i ' in dep: index_lookup[constraint.name] = project.get_source( url=dep.split(' -i ')[1]).get('name') if constraint.markers: markers_lookup[constraint.name] = str( constraint.markers).replace('"', "'") constraints.append(constraint) rmtree(req_dir) pip_command = get_pip_command() pip_args = [] if sources: pip_args = prepare_pip_source_args(sources, pip_args) if verbose: print('Using pip: {0}'.format(' '.join(pip_args))) pip_options, _ = pip_command.parse_args(pip_args) session = pip_command._build_session(pip_options) pypi = PyPIRepository(pip_options=pip_options, use_json=True, session=session) if verbose: logging.log.verbose = True piptools_logging.log.verbose = True resolved_tree = set() resolver = Resolver(constraints=constraints, repository=pypi, clear_caches=clear, prereleases=pre) # pre-resolve instead of iterating to avoid asking pypi for hashes of editable packages try: resolved_tree.update(resolver.resolve(max_rounds=PIPENV_MAX_ROUNDS)) except (NoCandidateFound, DistributionNotFound, HTTPError) as e: click.echo( '{0}: Your dependencies could not be resolved. You likely have a mismatch in your sub-dependencies.\n ' 'You can use {1} to bypass this mechanism, then run {2} to inspect the situation.' ''.format(crayons.red('Warning', bold=True), crayons.red('$ pipenv install --skip-lock'), crayons.red('$ pipenv graph')), err=True) click.echo(crayons.blue(str(e)), err=True) if 'no version found at all' in str(e): click.echo( crayons.blue( 'Please check your version specifier and version number. See PEP440 for more information.' )) raise RuntimeError return resolved_tree, resolver
def cli(verbose, dry_run, pre, rebuild, find_links, index_url, extra_index_url, cert, client_cert, trusted_host, header, index, emit_trusted_host, annotate, upgrade, upgrade_packages, output_file, allow_unsafe, generate_hashes, src_files, max_rounds): """Compiles requirements.txt from requirements.in specs.""" log.verbose = verbose if len(src_files) == 0: if os.path.exists(DEFAULT_REQUIREMENTS_FILE): src_files = (DEFAULT_REQUIREMENTS_FILE, ) elif os.path.exists('setup.py'): src_files = ('setup.py', ) if not output_file: output_file = 'requirements.txt' else: raise click.BadParameter(("If you do not specify an input file, " "the default is {} or setup.py" ).format(DEFAULT_REQUIREMENTS_FILE)) if len(src_files) == 1 and src_files[0] == '-': if not output_file: raise click.BadParameter( '--output-file is required if input is from stdin') if len(src_files) > 1 and not output_file: raise click.BadParameter( '--output-file is required if two or more input files are given.') if output_file: dst_file = output_file else: base_name = src_files[0].rsplit('.', 1)[0] 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 ### pip_command = get_pip_command() pip_args = [] if find_links: for link in find_links: pip_args.extend(['-f', link]) if index_url: pip_args.extend(['-i', index_url]) if extra_index_url: for extra_index in extra_index_url: pip_args.extend(['--extra-index-url', extra_index]) if cert: pip_args.extend(['--cert', cert]) if client_cert: pip_args.extend(['--client-cert', client_cert]) if pre: pip_args.extend(['--pre']) if trusted_host: for host in trusted_host: pip_args.extend(['--trusted-host', host]) pip_options, _ = pip_command.parse_args(pip_args) session = pip_command._build_session(pip_options) repository = PyPIRepository(pip_options, session) # 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(InstallRequirement.from_line(pkg).req) for pkg in upgrade_packages } 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 } repository = LocalRequirementsRepository(existing_pins, repository) log.debug('Using indexes:') # remove duplicate index urls before processing repository.finder.index_urls = list(dedup(repository.finder.index_urls)) for index_url in repository.finder.index_urls: log.debug(' {}'.format(index_url)) if repository.finder.find_links: log.debug('') log.debug('Configuration:') for find_link in repository.finder.find_links: log.debug(' -f {}'.format(find_link)) ### # Parsing/collecting initial requirements ### constraints = [] for src_file in src_files: is_setup_file = os.path.basename(src_file) == 'setup.py' if is_setup_file or src_file == '-': # 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. also used for # reading requirements from install_requires in setup.py. tmpfile = tempfile.NamedTemporaryFile(mode='wt', delete=False) if is_setup_file: from distutils.core import run_setup dist = run_setup(src_file) tmpfile.write('\n'.join(dist.install_requires)) else: tmpfile.write(sys.stdin.read()) tmpfile.flush() constraints.extend( parse_requirements(tmpfile.name, finder=repository.finder, session=repository.session, options=pip_options)) else: constraints.extend( parse_requirements(src_file, finder=repository.finder, session=repository.session, options=pip_options)) # 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() ] # Check the given base set of constraints first Resolver.check_constraints(constraints) try: resolver = Resolver(constraints, repository, prereleases=pre, clear_caches=rebuild, allow_unsafe=allow_unsafe) results = resolver.resolve(max_rounds=max_rounds) if generate_hashes: hashes = resolver.resolve_hashes(results) else: hashes = None except PipToolsError as e: log.error(str(e)) sys.exit(2) log.debug('') ## # Output ## # Compute reverse dependency annotations statically, from the # dependency cache that the resolver has populated by now. # # TODO (1a): reverse deps for any editable package are lost # what SHOULD happen is that they are cached in memory, just # not persisted to disk! # # TODO (1b): perhaps it's easiest if the dependency cache has an API # that could take InstallRequirements directly, like: # # cache.set(ireq, ...) # # then, when ireq is editable, it would store in # # editables[egg_name][link_without_fragment] = deps # editables['pip-tools']['git+...ols.git@future'] = {'click>=3.0', 'six'} # # otherwise: # # self[as_name_version_tuple(ireq)] = {'click>=3.0', 'six'} # reverse_dependencies = None if annotate: reverse_dependencies = resolver.reverse_dependencies(results) writer = OutputWriter(src_files, dst_file, dry_run=dry_run, emit_header=header, emit_index=index, emit_trusted_host=emit_trusted_host, annotate=annotate, generate_hashes=generate_hashes, default_index_url=repository.DEFAULT_INDEX_URL, index_urls=repository.finder.index_urls, trusted_hosts=pip_options.trusted_hosts, format_control=repository.finder.format_control) writer.write(results=results, unsafe_requirements=resolver.unsafe_constraints, reverse_dependencies=reverse_dependencies, primary_packages={ key_from_req(ireq.req) for ireq in constraints if not ireq.constraint }, markers={ key_from_req(ireq.req): ireq.markers for ireq in constraints if ireq.markers }, hashes=hashes, allow_unsafe=allow_unsafe) if dry_run: log.warning('Dry-run, so nothing updated.')