diff --git a/pipenv/cli.py b/pipenv/cli.py index bf3f225a..18322253 100644 --- a/pipenv/cli.py +++ b/pipenv/cli.py @@ -706,6 +706,8 @@ def get_downloads_info(names_map, section): def do_lock(verbose=False): """Executes the freeze functionality.""" + inline_activate_virtualenv() + # Alert the user of progress. click.echo( u'{0} {1} {2}'.format( @@ -719,37 +721,43 @@ def do_lock(verbose=False): # Create the lockfile. lockfile = project._lockfile - with spinner(): - # Cleanup lockfile. - for section in ('default', 'develop'): - for k, v in lockfile[section].copy().items(): - if not hasattr(v, 'keys'): - del lockfile[section][k] + # Cleanup lockfile. + for section in ('default', 'develop'): + for k, v in lockfile[section].copy().items(): + if not hasattr(v, 'keys'): + del lockfile[section][k] - # Resolve dev-package dependencies, with pip-tools. - deps = convert_deps_to_pip(project.dev_packages, r=False) - results = resolve_deps(deps, sources=project.sources, verbose=verbose) + # Resolve dev-package dependencies, with pip-tools. + deps = convert_deps_to_pip(project.dev_packages, r=False) + results = resolve_deps( + deps, + sources=project.sources, + verbose=verbose, + python=python_version( + which('python') if project.required_python_version else None + ) + ) - # Add develop dependencies to lockfile. - for dep in results: - lockfile['develop'].update({dep['name']: {'version': '=={0}'.format(dep['version'])}}) - lockfile['develop'][dep['name']]['hashes'] = dep['hashes'] + # Add develop dependencies to lockfile. + for dep in results: + lockfile['develop'].update({dep['name']: {'version': '=={0}'.format(dep['version'])}}) + lockfile['develop'][dep['name']]['hashes'] = dep['hashes'] - # Add refs for VCS installs. - # TODO: be smarter about this. - vcs_deps = convert_deps_to_pip(project.vcs_dev_packages, r=False) - pip_freeze = delegator.run('{0} freeze'.format(which_pip())).out + # Add refs for VCS installs. + # TODO: be smarter about this. + vcs_deps = convert_deps_to_pip(project.vcs_dev_packages, r=False) + pip_freeze = delegator.run('{0} freeze'.format(which_pip())).out - for dep in vcs_deps: - for line in pip_freeze.strip().split('\n'): - try: - installed = convert_deps_from_pip(line) - name = list(installed.keys())[0] + for dep in vcs_deps: + for line in pip_freeze.strip().split('\n'): + try: + installed = convert_deps_from_pip(line) + name = list(installed.keys())[0] - if is_vcs(installed[name]): - lockfile['develop'].update(installed) - except IndexError: - pass + if is_vcs(installed[name]): + lockfile['develop'].update(installed) + except IndexError: + pass # Alert the user of progress. click.echo( @@ -761,45 +769,50 @@ def do_lock(verbose=False): err=True ) - with spinner(): - # Resolve package dependencies, with pip-tools. - deps = convert_deps_to_pip(project.packages, r=False) - results = resolve_deps(deps, sources=project.sources) + # Resolve package dependencies, with pip-tools. + deps = convert_deps_to_pip(project.packages, r=False) + results = resolve_deps( + deps, + sources=project.sources, + verbose=verbose, + python=python_version( + which('python') if project.required_python_version else None + ) + ) - # Add default dependencies to lockfile. - for dep in results: - lockfile['default'].update({dep['name']: {'version': '=={0}'.format(dep['version'])}}) - lockfile['default'][dep['name']]['hashes'] = dep['hashes'] + # Add default dependencies to lockfile. + for dep in results: + lockfile['default'].update({dep['name']: {'version': '=={0}'.format(dep['version'])}}) + lockfile['default'][dep['name']]['hashes'] = dep['hashes'] - # Add refs for VCS installs. - # TODO: be smarter about this. - vcs_deps = convert_deps_to_pip(project.vcs_packages, r=False) - pip_freeze = delegator.run('{0} freeze'.format(which_pip())).out + # Add refs for VCS installs. + # TODO: be smarter about this. + vcs_deps = convert_deps_to_pip(project.vcs_packages, r=False) + pip_freeze = delegator.run('{0} freeze'.format(which_pip())).out - for dep in vcs_deps: - for line in pip_freeze.strip().split('\n'): - try: - installed = convert_deps_from_pip(line) - name = list(installed.keys())[0] + for dep in vcs_deps: + for line in pip_freeze.strip().split('\n'): + try: + installed = convert_deps_from_pip(line) + name = list(installed.keys())[0] - if is_vcs(installed[name]): - lockfile['default'].update(installed) - except IndexError: - pass + if is_vcs(installed[name]): + lockfile['default'].update(installed) + except IndexError: + pass - with spinner(): - # Run the PEP 508 checker in the virtualenv, add it to the lockfile. - cmd = '"{0}" {1}'.format(which('python'), shellquote(pep508checker.__file__.rstrip('cdo'))) - c = delegator.run(cmd) - lockfile['_meta']['host-environment-markers'] = json.loads(c.out) + # Run the PEP 508 checker in the virtualenv, add it to the lockfile. + cmd = '"{0}" {1}'.format(which('python'), shellquote(pep508checker.__file__.rstrip('cdo'))) + c = delegator.run(cmd) + lockfile['_meta']['host-environment-markers'] = json.loads(c.out) - # Write out the lockfile. - with open(project.lockfile_location, 'w') as f: - json.dump(lockfile, f, indent=4, separators=(',', ': '), sort_keys=True) - # Write newline at end of document. GH Issue #319. - f.write('\n') + # Write out the lockfile. + with open(project.lockfile_location, 'w') as f: + json.dump(lockfile, f, indent=4, separators=(',', ': '), sort_keys=True) + # Write newline at end of document. GH Issue #319. + f.write('\n') - click.echo('{0}'.format(crayons.white('Updated Pipfile.lock!', bold=True)), err=True) + click.echo('{0}'.format(crayons.white('Updated Pipfile.lock!', bold=True)), err=True) def activate_virtualenv(source=True): diff --git a/pipenv/utils.py b/pipenv/utils.py index f6b7ed24..f8f45236 100644 --- a/pipenv/utils.py +++ b/pipenv/utils.py @@ -1,17 +1,13 @@ # -*- coding: utf-8 -*- +import sys import os import hashlib import tempfile - -from piptools.resolver import Resolver -from piptools.repositories.pypi import PyPIRepository -from piptools.scripts.compile import get_pip_command -from piptools import logging +from collections import namedtuple import delegator import requests import parse -import pip import six # List of version control systems we support. @@ -21,11 +17,6 @@ FILE_LIST = ('http://', 'https://', 'ftp://', 'file:///') requests = requests.session() -class PipCommand(pip.basecommand.Command): - """Needed for pip-tools.""" - name = 'PipCommand' - - def python_version(path_to_python): try: TEMPLATE = 'Python {}.{}.{}' @@ -50,11 +41,32 @@ def clean_pkg_version(version): return six.u(pep440_version(str(version).replace('==', ''))) -def resolve_deps(deps, sources=None, verbose=False): +def resolve_deps(deps, sources=None, verbose=False, python=False): """Given a list of dependencies, return a resolved list of dependencies, using pip-tools -- and their hashes, using the warehouse API / pip. """ + # If a version of python is required... + if python: + original_sys_info = sys.version_info + sys.version_info = namedtuple('fake_version_info', ['major', 'minor', 'micro', 'releaselevel', 'serial']) + + python = python.split('.') + + # Hack sys.version_info to contain our information instead... + sys.version_info = sys.version_info(int(python[0]), int(python[1]), int(python[2]), 'final', 0) + + import pip + + class PipCommand(pip.basecommand.Command): + """Needed for pip-tools.""" + name = 'PipCommand' + + from piptools.resolver import Resolver + from piptools.repositories.pypi import PyPIRepository + from piptools.scripts.compile import get_pip_command + from piptools import logging + constraints = [] for dep in deps: @@ -113,6 +125,9 @@ def resolve_deps(deps, sources=None, verbose=False): results.append({'name': name, 'version': version, 'hashes': collected_hashes}) + # Restore to original state. + sys.version_info = original_sys_info + return results @@ -325,7 +340,7 @@ def is_file(package): def pep440_version(version): """Normalize version to PEP 440 standards""" - + import pip # Use pip built-in version parser. return str(pip.index.parse_version(version))