From 0674ec8e375c7cecae3146b477c225180059561a Mon Sep 17 00:00:00 2001 From: Kenneth Reitz Date: Tue, 25 Apr 2017 10:50:11 -0400 Subject: [PATCH 1/4] basic machinery for pip file importing in place, now to import --- pipenv/cli.py | 4 ++++ pipenv/project.py | 18 +++++++++++++++++- pipenv/utils.py | 46 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 67 insertions(+), 1 deletion(-) diff --git a/pipenv/cli.py b/pipenv/cli.py index 52763f30..e79f5852 100644 --- a/pipenv/cli.py +++ b/pipenv/cli.py @@ -90,6 +90,10 @@ def ensure_pipfile(validate=True): # Assert Pipfile exists. if not project.pipfile_exists: + if project.requirements_exists: + print 'requirements file found! importing...' + exit() + click.echo(crayons.yellow('Creating a Pipfile for this project...'), err=True) # Create the pipfile if it doesn't exist. diff --git a/pipenv/project.py b/pipenv/project.py index ab103aaa..855532d4 100644 --- a/pipenv/project.py +++ b/pipenv/project.py @@ -12,7 +12,7 @@ import delegator from requests.compat import OrderedDict from .utils import (format_toml, mkdir_p, convert_deps_from_pip, - pep423_name, recase_file) + pep423_name, recase_file, find_requirements) from .environments import PIPENV_MAX_DEPTH, PIPENV_VENV_IN_PROJECT @@ -25,6 +25,7 @@ class Project(object): self._download_location = None self._proper_names_location = None self._pipfile_location = None + self._requirements_location = None @property def name(self): @@ -36,6 +37,10 @@ class Project(object): def pipfile_exists(self): return bool(self.pipfile_location) + @property + def requirements_exists(self): + return bool(self.requirements_location) + @property def virtualenv_exists(self): # TODO: Decouple project from existence of Pipfile. @@ -128,6 +133,17 @@ class Project(object): return self._pipfile_location + @property + def requirements_location(self): + if self._requirements_location is None: + try: + loc = find_requirements(max_depth=PIPENV_MAX_DEPTH) + except RuntimeError: + loc = None + self._requirements_location = loc + + return self._requirements_location + @property def parsed_pipfile(self): with open(self.pipfile_location) as f: diff --git a/pipenv/utils.py b/pipenv/utils.py index 6822a942..d1da2faf 100644 --- a/pipenv/utils.py +++ b/pipenv/utils.py @@ -235,3 +235,49 @@ def recase_file(file_dict): file_section[cased_key] = file_section.pop(key) return file_dict + + +def walk_up(bottom): + """mimic os.walk, but walk 'up' instead of down the directory tree. + From: https://gist.github.com/zdavkeos/1098474 + """ + + bottom = os.path.realpath(bottom) + + # get files in current dir + try: + names = os.listdir(bottom) + except Exception as e: + return + + dirs, nondirs = [], [] + for name in names: + if os.path.isdir(os.path.join(bottom, name)): + dirs.append(name) + else: + nondirs.append(name) + + yield bottom, dirs, nondirs + + new_path = os.path.realpath(os.path.join(bottom, '..')) + + # see if we are at the top + if new_path == bottom: + return + + for x in walk_up(new_path): + yield x + + +def find_requirements(max_depth=3): + """Returns the path of a Pipfile in parent directories.""" + i = 0 + for c, d, f in walk_up(os.getcwd()): + i += 1 + + if i < max_depth: + if 'requirements.txt': + r = os.path.join(c, 'requirements.txt') + if os.path.isfile(r): + return r + raise RuntimeError('No requirements.txt found!') From 1477fc72949c37fb3f7182cb321277c9efb67974 Mon Sep 17 00:00:00 2001 From: Kenneth Reitz Date: Wed, 26 Apr 2017 11:08:32 -0400 Subject: [PATCH 2/4] changes --- pipenv/cli.py | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/pipenv/cli.py b/pipenv/cli.py index e79f5852..889e94b9 100644 --- a/pipenv/cli.py +++ b/pipenv/cli.py @@ -91,13 +91,21 @@ def ensure_pipfile(validate=True): if not project.pipfile_exists: if project.requirements_exists: - print 'requirements file found! importing...' + click.echo(crayons.yellow('Requirements file found, instead of Pipfile! Converting...')) + project.create_pipfile() + click.echo(crayons.yellow('Installing dependencies from \'requirements.txt\'...')) + print '{0} install -r {1}'.format(which('pip'), project.requirements_location) + delegator.run('{0} install -r {1}'.format(which('pip'), project.requirements_location)) + for line in delegator.run('{0} freeze'.format(which('pip'))).out.split('\n'): + if line: + print convert_deps_from_pip(line) + exit() - click.echo(crayons.yellow('Creating a Pipfile for this project...'), err=True) - - # Create the pipfile if it doesn't exist. - project.create_pipfile() + else: + click.echo(crayons.yellow('Creating a Pipfile for this project...'), err=True) + # Create the pipfile if it doesn't exist. + project.create_pipfile() # Validate the Pipfile's contents. if validate and project.virtualenv_exists: From 05e18ffec25a7f4cd3f11d85a233eaa727fe6f1e Mon Sep 17 00:00:00 2001 From: Kenneth Reitz Date: Wed, 26 Apr 2017 15:36:15 -0400 Subject: [PATCH 3/4] it works! --- pipenv/cli.py | 31 ++++++++++++++++++++++--------- 1 file changed, 22 insertions(+), 9 deletions(-) diff --git a/pipenv/cli.py b/pipenv/cli.py index 889e94b9..e5d0daf3 100644 --- a/pipenv/cli.py +++ b/pipenv/cli.py @@ -38,6 +38,9 @@ else: # |_| |_|| _/|___>|_|_||__/ # |_| +# Packages that should be ignored later. +BAD_PACKAGES = ['setuptools', 'pip', 'wheel', 'six', 'packaging', 'pyparsing', 'appdirs'] + # Enable shell completion. click_completion.init() @@ -90,17 +93,28 @@ def ensure_pipfile(validate=True): # Assert Pipfile exists. if not project.pipfile_exists: + # If there's a requirements file, but no Pipfile... if project.requirements_exists: click.echo(crayons.yellow('Requirements file found, instead of Pipfile! Converting...')) + + # Create a Pipfile... project.create_pipfile() - click.echo(crayons.yellow('Installing dependencies from \'requirements.txt\'...')) - print '{0} install -r {1}'.format(which('pip'), project.requirements_location) - delegator.run('{0} install -r {1}'.format(which('pip'), project.requirements_location)) - for line in delegator.run('{0} freeze'.format(which('pip'))).out.split('\n'): - if line: - print convert_deps_from_pip(line) - exit() + click.echo(crayons.yellow('Installing dependencies from \'requirements.txt\'...')) + + # Install everything from the requirements.txt. + delegator.run('{0} install -r {1}'.format(which('pip'), project.requirements_location)) + installed = delegator.run('{0} freeze'.format(which('pip'))).out.split('\n') + + # Remove setuptools and friends from installed, if present. + for package_name in BAD_PACKAGES: + for i, package in enumerate(installed): + if package.startswith(package_name): + del installed[i] + + for package in installed: + if package: + project.add_package_to_pipfile(package) else: click.echo(crayons.yellow('Creating a Pipfile for this project...'), err=True) @@ -537,7 +551,6 @@ def do_activate_virtualenv(bare=False): else: click.echo(activate_virtualenv()) - def do_purge(bare=False, downloads=False, allow_global=False): """Executes the purge functionality.""" @@ -551,7 +564,7 @@ def do_purge(bare=False, downloads=False, allow_global=False): installed = freeze.split() # Remove setuptools and friends from installed, if present. - for package_name in ['setuptools', 'pip', 'wheel', 'six', 'packaging', 'pyparsing', 'appdirs']: + for package_name in BAD_PACKAGES: for i, package in enumerate(installed): if package.startswith(package_name): del installed[i] From 52464792671ea332b04bae90e3462e2980127042 Mon Sep 17 00:00:00 2001 From: Kenneth Reitz Date: Wed, 26 Apr 2017 15:40:27 -0400 Subject: [PATCH 4/4] making history Signed-off-by: Kenneth Reitz --- HISTORY.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/HISTORY.txt b/HISTORY.txt index 86e15e23..610ed88a 100644 --- a/HISTORY.txt +++ b/HISTORY.txt @@ -1,3 +1,5 @@ +3.6.1: + - pipenv install now works if only a requirements.txt is present. 3.6.0: - Make --two/--three handling more consistent. - Update vendored delegator.py.