diff --git a/HISTORY.txt b/HISTORY.txt index e874e07f..a542966f 100644 --- a/HISTORY.txt +++ b/HISTORY.txt @@ -1,3 +1,5 @@ +11.9.1: + - Resolve editable packages on the local filesystem. 11.9.0: - Vastly improve markers capabilities. - Support for environment variables in Pipfiles. diff --git a/pipenv/__version__.py b/pipenv/__version__.py index 6aa4cc6c..223d1649 100644 --- a/pipenv/__version__.py +++ b/pipenv/__version__.py @@ -2,4 +2,4 @@ # // ) ) / / // ) ) //___) ) // ) ) || / / # //___/ / / / //___/ / // // / / || / / # // / / // ((____ // / / ||/ / -__version__ = '11.9.0' +__version__ = '11.9.1' diff --git a/pipenv/core.py b/pipenv/core.py index 3cb8b6cd..e1a82e5a 100644 --- a/pipenv/core.py +++ b/pipenv/core.py @@ -169,8 +169,6 @@ def add_to_path(p): ) - - def cleanup_virtualenv(bare=True): """Removes the virtualenv directory from the system.""" if not bare: @@ -1346,7 +1344,7 @@ def do_init( ), err=True, ) - do_lock(system=system, pre=pre) + do_lock(system=system, pre=pre, keep_outdated=keep_outdated) # Write out the lockfile if it doesn't exist. if not project.lockfile_exists and not skip_lock: click.echo( @@ -1635,6 +1633,7 @@ def format_pip_output(out, r=None): out = '\n'.join([l for l in gen(out)]) return out + def warn_in_virtualenv(): if PIPENV_USE_SYSTEM: # Only warn if pipenv isn't already active. @@ -1865,6 +1864,20 @@ def do_install( # Capture . argument and assign it to nothing if package_name == '.': package_name = False + # Install editable local packages before locking - this givves us acceess to dist-info + if project.pipfile_exists and ( + not project.lockfile_exists or not project.virtualenv_exists + ): + section = project.editable_packages if not dev else project.dev_editable_packages + for package in section.keys(): + converted = convert_deps_to_pip( + {package: section[package]}, project=project, r=False + ) + if not package_name: + if converted: + package_name = converted.pop(0) + if converted: + more_packages.extend(converted) # Allow more than one package to be provided. package_names = [package_name] + more_packages # Install all dependencies, if none was provided. @@ -1899,7 +1912,9 @@ def do_install( ): # Support for VCS dependencies. package_names[i] = convert_deps_to_pip( - {package_name: section[package__name]}, r=False + {package_name: section[package__name]}, + project=project, + r=False, )[ 0 ] @@ -2446,12 +2461,12 @@ def do_clean( # Ensure that virtualenv is available. ensure_project(three=three, python=python, validate=False) ensure_lockfile() - installed_packages = filter(None, delegator.run( - '{0} freeze'.format(which('pip')) - ).out.strip( - ).split( - '\n' - )) + installed_packages = filter( + None, + delegator.run('{0} freeze'.format(which('pip'))).out.strip().split( + '\n' + ), + ) installed_package_names = [] for installed in installed_packages: r = get_requirement(installed) diff --git a/pipenv/project.py b/pipenv/project.py index 812a9841..caee5007 100644 --- a/pipenv/project.py +++ b/pipenv/project.py @@ -28,6 +28,7 @@ from .utils import ( normalize_drive, python_version, escape_grouped_arguments, + VCS_LIST, ) from .environments import ( PIPENV_MAX_DEPTH, @@ -45,8 +46,6 @@ if PIPENV_PIPFILE: else: PIPENV_PIPFILE = normalize_drive(os.path.abspath(PIPENV_PIPFILE)) - - # (path, file contents) => TOMLFile # keeps track of pipfiles that we've seen so we do not need to re-parse 'em _pipfile_cache = {} @@ -411,7 +410,33 @@ class Project(object): @property def lockfile_content(self): with open(self.lockfile_location) as lock: - return json.load(lock) + j = json.load(lock) + + # Expand environment variables in Pipfile.lock at runtime. + for i, source in enumerate(j['_meta']['sources'][:]): + j['_meta']['sources'][i]['url'] = os.path.expandvars(j['_meta']['sources'][i]['url']) + + return j + + @property + def editable_packages(self): + packages = {} + for k, v in self.parsed_pipfile.get('packages', {}).items(): + if v.get('editable') and any( + v.get(key) for key in ('file', 'path') + VCS_LIST + ): + packages.update({k: v}) + return packages + + @property + def editable_dev_packages(self): + packages = {} + for k, v in self.parsed_pipfile.get('dev-packages', {}).items(): + if v.get('editable') and any( + v.get(key) for key in ('file', 'path') + VCS_LIST + ): + packages.update({k: v}) + return packages @property def vcs_packages(self):