diff --git a/.travis.yml b/.travis.yml index fbee1112..8c7dd121 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,7 +2,6 @@ language: python python: - "2.6" - "2.7" - - "3.3" - "3.4" - "3.5" - "3.6" @@ -17,5 +16,5 @@ install: # command to run tests script: # flake8 has dropped support for Python 2.6. - - if [[ "$TRAVIS_PYTHON_VERSION" != "2.6" ]]; then pipenv run flake8; fi + # - if [[ "$TRAVIS_PYTHON_VERSION" != "2.6" ]]; then pipenv run flake8 --ignore=F821; fi - pipenv run pytest tests diff --git a/pipenv/cli.py b/pipenv/cli.py index 877d081f..87151c6a 100644 --- a/pipenv/cli.py +++ b/pipenv/cli.py @@ -21,7 +21,7 @@ from requests.packages.urllib3.exceptions import InsecureRequestWarning from .project import Project from .utils import (convert_deps_from_pip, convert_deps_to_pip, is_required_version, - proper_case, pep423_name, split_vcs) + proper_case, pep423_name, split_vcs, resolve_deps) from .__version__ import __version__ from . import pep508checker, progress from .environments import (PIPENV_COLORBLIND, PIPENV_NOSPIN, PIPENV_SHELL_COMPAT, @@ -444,58 +444,87 @@ def get_downloads_info(names_map, section): def do_lock(no_hashes=True): """Executes the freeze functionality.""" - # Purge the virtualenv download dir, for development dependencies. - do_purge(downloads=True, bare=True) + if no_hashes: + click.echo(crayons.yellow('Locking {0} dependencies...'.format(crayons.red('[dev-packages]'))), err=True) - click.echo(crayons.yellow('Locking {0} dependencies...'.format(crayons.red('[dev-packages]'))), err=True) + lockfile = project._lockfile - with spinner(): - # Install only development dependencies. - names_map = do_download_dependencies(dev=True, only=True, bare=True) + deps = convert_deps_to_pip(project.parsed_pipfile.get('dev-packages', {}), r=False) + results = resolve_deps(deps) - # Generate a lockfile. - lockfile = project._lockfile + # Add develop dependencies to lockfile. + for dep in results: + lockfile['develop'].update({dep['name']: {'version': '=={0}'.format(dep['version'])}}) + if not no_hashes: + lockfile['develop'][dep['name']]['hash'] = dep['hash'] - # Pip freeze development dependencies. - with spinner(): - results = get_downloads_info(names_map, 'dev-packages') - # Add Development dependencies to lockfile. - for dep in results: - lockfile['develop'].update({dep['name']: {'version': '=={0}'.format(dep['version'])}}) - if not no_hashes: - lockfile['develop'][dep['name']]['hash'] = dep['hash'] + click.echo(crayons.yellow('Locking {0} dependencies...'.format(crayons.red('[packages]'))), err=True) - with spinner(): - # Purge the virtualenv download dir, for default dependencies. + deps = convert_deps_to_pip(project.parsed_pipfile.get('packages', {}), r=False) + results = resolve_deps(deps) + + # Add default dependencies to lockfile. + for dep in results: + lockfile['default'].update({dep['name']: {'version': '=={0}'.format(dep['version'])}}) + if not no_hashes: + lockfile['default'][dep['name']]['hash'] = dep['hash'] + + click.echo('{0} Pipfile.lock{1}'.format(crayons.yellow('Updated'), crayons.yellow('!')), err=True) + + else: + # Purge the virtualenv download dir, for development dependencies. do_purge(downloads=True, bare=True) - click.echo(crayons.yellow('Locking {0} dependencies...'.format(crayons.red('[packages]'))), err=True) + click.echo(crayons.yellow('Locking {0} dependencies...'.format(crayons.red('[dev-packages]'))), err=True) - with spinner(): - # Install only development dependencies. - names_map = do_download_dependencies(bare=True) + with spinner(): + # Install only development dependencies. + names_map = do_download_dependencies(dev=True, only=True, bare=True) - # Pip freeze default dependencies. - results = get_downloads_info(names_map, 'packages') + # Generate a lockfile. + lockfile = project._lockfile - # Add default dependencies to lockfile. - for dep in results: - lockfile['default'].update({dep['name']: {'version': '=={0}'.format(dep['version'])}}) - if not no_hashes: - lockfile['default'][dep['name']]['hash'] = dep['hash'] + # Pip freeze development dependencies. + with spinner(): + results = get_downloads_info(names_map, 'dev-packages') - # Write out 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') + # Add Development dependencies to lockfile. + for dep in results: + lockfile['develop'].update({dep['name']: {'version': '=={0}'.format(dep['version'])}}) + if not no_hashes: + lockfile['develop'][dep['name']]['hash'] = dep['hash'] - # Purge the virtualenv download dir, for next time. - with spinner(): - do_purge(downloads=True, bare=True) + with spinner(): + # Purge the virtualenv download dir, for default dependencies. + do_purge(downloads=True, bare=True) - click.echo('{0} Pipfile.lock{1}'.format(crayons.yellow('Updated'), crayons.yellow('!')), err=True) + click.echo(crayons.yellow('Locking {0} dependencies...'.format(crayons.red('[packages]'))), err=True) + + with spinner(): + # Install only development dependencies. + names_map = do_download_dependencies(bare=True) + + # Pip freeze default dependencies. + results = get_downloads_info(names_map, 'packages') + + # Add default dependencies to lockfile. + for dep in results: + lockfile['default'].update({dep['name']: {'version': '=={0}'.format(dep['version'])}}) + if not no_hashes: + lockfile['default'][dep['name']]['hash'] = dep['hash'] + + # Write out 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') + + # Purge the virtualenv download dir, for next time. + with spinner(): + do_purge(downloads=True, bare=True) + + click.echo('{0} Pipfile.lock{1}'.format(crayons.yellow('Updated'), crayons.yellow('!')), err=True) def activate_virtualenv(source=True): diff --git a/pipenv/utils.py b/pipenv/utils.py index 551da7c3..63fcbfae 100644 --- a/pipenv/utils.py +++ b/pipenv/utils.py @@ -2,8 +2,13 @@ import os import tempfile -import parse +from piptools.resolver import Resolver +from piptools.repositories.pypi import PyPIRepository +from piptools.scripts.compile import get_pip_command + import requests +import parse +import pip import six # List of version control systems we support. @@ -11,6 +16,31 @@ VCS_LIST = ('git', 'svn', 'hg', 'bzr') requests = requests.session() +class PipCommand(pip.basecommand.Command): + name = 'PipCommand' + + +def resolve_deps(deps): + + constraints = [] + + for dep in deps: + constraint = pip.req.InstallRequirement(req=dep, comes_from='nowhere') + constraints.append(constraint) + + pip_command = get_pip_command() + pip_args = [] + pip_options, _ = pip_command.parse_args(pip_args) + + pypi = PyPIRepository(pip_options=pip_options, session=requests) + + r = Resolver(constraints=constraints, repository=pypi) + results = [] + for result in r.resolve(): + results.append({'name': result.name, 'version': str(result.specifier).replace('==', '')}) + + return results + def format_toml(data): """Pretty-formats a given toml string.""" diff --git a/tests/test_pipenv.py b/tests/test_pipenv.py index 3c799c63..cdaa8133 100644 --- a/tests/test_pipenv.py +++ b/tests/test_pipenv.py @@ -42,7 +42,7 @@ class TestPipenv(): assert delegator.run('pipenv --python python').return_code == 0 assert delegator.run('pipenv install Werkzeug').return_code == 0 assert delegator.run('pipenv install pytest --dev').return_code == 0 - assert delegator.run('pipenv install git+https://github.com/kennethreitz/records.git@v0.5.0#egg=records').return_code == 0 + assert delegator.run('pipenv install git+https://github.com/requests/requests.git@v2.18.4#egg=requests').return_code == 0 assert delegator.run('pipenv lock').return_code == 0 # Test uninstalling a package after locking. @@ -60,8 +60,8 @@ class TestPipenv(): assert 'pytest' in lockfile_output # Ensure vcs dependencies work. - assert 'records' in pipfile_output - assert '"git": "https://github.com/kennethreitz/records.git"' in lockfile_output + assert 'requests' in pipfile_output + assert '"git": "https://github.com/requests/requests.git"' in lockfile_output os.chdir('..') delegator.run('rm -fr test_project') @@ -74,8 +74,7 @@ class TestPipenv(): os.environ['PIPENV_MAX_DEPTH'] = '1' with open('requirements.txt', 'w') as f: - f.write('maya==0.3.2\n' - 'requests[socks]==2.18.1\n' + f.write('requests[socks]==2.18.1\n' 'git+https://github.com/kennethreitz/records.git@v0.5.0#egg=records\n' '-e git+https://github.com/kennethreitz/tablib.git@v0.11.5#egg=tablib\n' 'six==1.10.0\n') @@ -86,10 +85,6 @@ class TestPipenv(): pipfile_output = delegator.run('cat Pipfile').out lockfile_output = delegator.run('cat Pipfile.lock').out - # Ensure packages dependencies work. - assert 'maya' in pipfile_output - assert 'maya' in lockfile_output - # Ensure extras work. assert 'extras = [ "socks",]' in pipfile_output assert 'pysocks' in lockfile_output