From b959ea476879582717c50b97efeb483842a2d911 Mon Sep 17 00:00:00 2001 From: Kenneth Reitz Date: Wed, 13 Sep 2017 12:11:48 -0400 Subject: [PATCH] default version of python in pipfile Signed-off-by: Kenneth Reitz --- pipenv/cli.py | 37 ++++++++++++++++--------------------- pipenv/project.py | 40 ++++++++++++++++++++++++++++++++++++---- pipenv/utils.py | 15 +++++++++++++++ 3 files changed, 67 insertions(+), 25 deletions(-) diff --git a/pipenv/cli.py b/pipenv/cli.py index 40df4e06..89b40bc7 100644 --- a/pipenv/cli.py +++ b/pipenv/cli.py @@ -29,7 +29,8 @@ from pip.req.req_file import parse_requirements from .project import Project from .utils import ( convert_deps_from_pip, convert_deps_to_pip, is_required_version, - proper_case, pep423_name, split_vcs, resolve_deps, shellquote, is_vcs + proper_case, pep423_name, split_vcs, resolve_deps, shellquote, is_vcs, + python_version ) from .__version__ import __version__ from . import pep508checker, progress @@ -234,14 +235,14 @@ def ensure_pipfile(validate=True): """Creates a Pipfile for the project, if it doesn't exist.""" # Assert Pipfile exists. - if not project.pipfile_exists: + if project.pipfile_is_empty: # If there's a requirements file, but no Pipfile... if project.requirements_exists: click.echo(crayons.white(u'Requirements.txt found, instead of Pipfile! Converting…', bold=True)) # Create a Pipfile... - project.create_pipfile() + project.create_pipfile(python=which('python')) # Import requirements.txt. import_requirements() @@ -249,7 +250,7 @@ def ensure_pipfile(validate=True): else: click.echo(crayons.white(u'Creating a Pipfile for this project…', bold=True), err=True) # Create the pipfile if it doesn't exist. - project.create_pipfile() + project.create_pipfile(python=which('python')) # Validate the Pipfile's contents. if validate and project.virtualenv_exists and not PIPENV_SKIP_VALIDATION: @@ -263,16 +264,6 @@ def ensure_pipfile(validate=True): project.write_toml(p) -def python_version(path_to_python): - try: - c = delegator.run('{0} --version'.format(path_to_python), block=False) - c.return_code == 0 - except Exception: - return None - - return str(c.out.strip() or c.err.strip()) - - def find_a_system_python(python): if python.startswith('py'): return system_which(python) @@ -352,7 +343,7 @@ def ensure_virtualenv(three=None, python=None): def ensure_project(three=None, python=None, validate=True, system=False, warn=True): """Ensures both Pipfile and virtualenv exist for the project.""" - ensure_pipfile(validate=validate) + project.touch_pipfile() # Skip virtualenv creation when --system was used. if not system: @@ -378,6 +369,9 @@ def ensure_project(three=None, python=None, validate=True, system=False, warn=Tr ''.format(crayons.red('$ pipenv check')) ) + # Ensure the Pipfile exists. + ensure_pipfile(validate=validate) + def ensure_proper_casing(pfile): """Ensures proper casing of Pipfile packages, writes changes to disk.""" @@ -846,12 +840,6 @@ def do_init( ): """Executes the init functionality.""" - ensure_pipfile() - - # Display where the Project is established. - if not requirements: - do_where(bare=False) - if not project.virtualenv_exists: try: do_create_virtualenv() @@ -859,6 +847,13 @@ def do_init( cleanup_virtualenv(bare=False) sys.exit(1) + # Ensure the Pipfile exists. + ensure_pipfile() + + # Display where the Project is established. + if not requirements: + do_where(bare=False) + # Write out the lockfile if it doesn't exist, but not if the Pipfile is being ignored if (project.lockfile_exists and not ignore_pipfile) and not skip_lock: diff --git a/pipenv/project.py b/pipenv/project.py index e496844a..451248f2 100644 --- a/pipenv/project.py +++ b/pipenv/project.py @@ -14,7 +14,7 @@ from requests.compat import OrderedDict from .utils import ( format_toml, mkdir_p, convert_deps_from_pip, pep423_name, recase_file, - find_requirements, is_file, is_vcs + find_requirements, is_file, is_vcs, python_version ) from .environments import PIPENV_MAX_DEPTH, PIPENV_VENV_IN_PROJECT from .environments import PIPENV_USE_SYSTEM @@ -52,7 +52,9 @@ class Project(object): @property def required_python_version(self): if self.pipfile_exists: - return self.parsed_pipfile.get('requires', {}).get('python_version') + required = self.parsed_pipfile.get('requires', {}).get('python_version') + if required != "*": + return required @property def project_directory(self): @@ -254,11 +256,41 @@ class Project(object): ps.update({k: v}) return ps - def create_pipfile(self): - data = {u'source': [{u'url': u'https://pypi.python.org/simple', u'verify_ssl': True}], u'packages': {}, 'dev-packages': {}} + def touch_pipfile(self): + """Simply touches the Pipfile, for later use.""" + with open('Pipfile', 'a'): + os.utime('Pipfile', None) + + @property + def pipfile_is_empty(self): + self.touch_pipfile() + + with open('Pipfile', 'r') as f: + if not f.read(): + return True + + def create_pipfile(self, python=None): + """Creates the Pipfile, filled with juicy defaults.""" + data = { + # Default source. + u'source': [ + {u'url': u'https://pypi.python.org/simple', u'verify_ssl': True} + ], + + # Default packages. + u'packages': {}, + u'dev-packages': {}, + + # Default requires. + } + + if python: + data[u'requires'] = {'python_version': python_version(python)[:len('2.7')]} + self.write_toml(data, 'Pipfile') def write_toml(self, data, path=None): + """Writes the given data structure out as TOML.""" if path is None: path = self.pipfile_location diff --git a/pipenv/utils.py b/pipenv/utils.py index 98e42f6e..d2828e69 100644 --- a/pipenv/utils.py +++ b/pipenv/utils.py @@ -8,6 +8,7 @@ from piptools.repositories.pypi import PyPIRepository from piptools.scripts.compile import get_pip_command from piptools import logging +import delegator import requests import parse import pip @@ -25,6 +26,20 @@ class PipCommand(pip.basecommand.Command): name = 'PipCommand' +def python_version(path_to_python): + try: + TEMPLATE = 'Python {}.{}.{}' + c = delegator.run('{0} --version'.format(path_to_python), block=False) + c.return_code == 0 + except Exception: + return None + + output = c.out.strip() or c.err.strip() + parsed = parse.parse(TEMPLATE, output).fixed + + return u"{v[0]}.{v[1]}.{v[2]}".format(v=parsed) + + def shellquote(s): """Prepares a string for the shell (on Windows too!)""" return '"' + s.replace("'", "'\\''") + '"'