Merge branch 'master' into test-fixes

This commit is contained in:
Dan Ryan
2018-04-10 23:29:14 -04:00
committed by GitHub
3 changed files with 119 additions and 70 deletions
+5 -43
View File
@@ -290,8 +290,7 @@ def ensure_pipfile(validate=True, skip_requirements=False):
if validate and project.virtualenv_exists and not PIPENV_SKIP_VALIDATION:
# Ensure that Pipfile is using proper casing.
p = project.parsed_pipfile
p.clear_pipfile_cache()
changed = ensure_proper_casing(pfile=p)
changed = project.ensure_proper_casing()
# Write changes out to disk.
if changed:
click.echo(
@@ -635,42 +634,6 @@ def ensure_project(
ensure_pipfile(validate=validate, skip_requirements=skip_requirements)
def ensure_proper_casing(pfile):
"""Ensures proper casing of Pipfile packages, writes changes to disk."""
casing_changed = proper_case_section(pfile.get('packages', {}))
casing_changed |= proper_case_section(pfile.get('dev-packages', {}))
return casing_changed
def proper_case_section(section):
"""Verify proper casing is retrieved, when available, for each
dependency in the section.
"""
# Casing for section.
changed_values = False
unknown_names = [
k for k in section.keys() if k not in set(project.proper_names)
]
# Replace each package with proper casing.
for dep in unknown_names:
try:
# Get new casing for package name.
new_casing = proper_case(dep)
except IOError:
# Unable to normalize package name.
continue
if new_casing != dep:
changed_values = True
project.register_proper_name(new_casing)
# Replace old value with new value.
old_value = section[dep]
section[new_casing] = old_value
del section[dep]
# Return whether or not values have been changed.
return changed_values
def shorten_path(location, bold=False):
"""Returns a visually shorter representation of a given system path."""
original = location
@@ -2075,11 +2038,10 @@ def do_uninstall(
c = delegator.run(cmd)
click.echo(crayons.blue(c.out))
if pipfile_remove:
norm_name = pep423_name(package_name)
in_dev_packages = (
norm_name in project._pipfile.get('dev-packages', {})
)
in_packages = (norm_name in project._pipfile.get('packages', {}))
in_packages = project.get_package_name_in_pipfile(
package_name, dev=False)
in_dev_packages = project.get_package_name_in_pipfile(
package_name, dev=True)
if not in_dev_packages and not in_packages:
click.echo(
'No package {0} to remove from Pipfile.'.format(
+62 -27
View File
@@ -3,7 +3,6 @@ import codecs
import json
import os
import re
import six
import sys
import shlex
import base64
@@ -21,7 +20,7 @@ from .utils import (
mkdir_p,
convert_deps_from_pip,
pep423_name,
recase_file,
proper_case,
find_requirements,
is_editable,
is_file,
@@ -370,20 +369,6 @@ class Project(object):
except Exception:
return toml.loads(contents)
@property
def _pipfile(self):
"""Pipfile divided by PyPI and external dependencies."""
pfile = self.parsed_pipfile
# mutation time!
self.clear_pipfile_cache()
for section in ('packages', 'dev-packages'):
p_section = dict(pfile.get(section, {}))
for key in list(p_section.keys()):
# Normalize key name to PEP 423.
norm_key = pep423_name(key)
p_section[norm_key] = p_section.pop(key)
return pfile
@property
def settings(self):
"""A dictionary of the settings added to the Pipfile."""
@@ -416,7 +401,6 @@ class Project(object):
p['pipenv'] = settings
# Write the changes to disk.
self.write_toml(p)
self.clear_pipfile_cache()
@property
def _lockfile(self):
@@ -572,6 +556,8 @@ class Project(object):
formatted_data = cleanup_toml(formatted_data)
with open(path, 'w') as f:
f.write(formatted_data)
# pipfile is mutated!
self.clear_pipfile_cache()
@property
def sources(self):
@@ -605,19 +591,28 @@ class Project(object):
except OSError:
pass
def get_package_name_in_pipfile(self, package_name, dev=False):
"""Get the equivalent package name in pipfile"""
key = 'dev-packages' if dev else 'packages'
section = self.parsed_pipfile.get(key, {})
package_name = pep423_name(package_name)
for name in section.keys():
if pep423_name(name) == package_name:
return name
return None
def remove_package_from_pipfile(self, package_name, dev=False):
# Read and append Pipfile.
p = self._pipfile
package_name = pep423_name(package_name)
name = self.get_package_name_in_pipfile(package_name, dev)
key = 'dev-packages' if dev else 'packages'
if key in p and package_name in p[key]:
del p[key][package_name]
# Write Pipfile.
self.write_toml(recase_file(p))
p = self.parsed_pipfile
if name:
del p[key][name]
self.write_toml(p)
def add_package_to_pipfile(self, package_name, dev=False):
# Read and append Pipfile.
p = self._pipfile
p = self.parsed_pipfile
# Don't re-capitalize file URLs or VCSs.
converted = convert_deps_from_pip(package_name)
converted = converted[[k for k in converted.keys()][0]]
@@ -631,15 +626,19 @@ class Project(object):
p[key] = {}
package = convert_deps_from_pip(package_name)
package_name = [k for k in package.keys()][0]
name = self.get_package_name_in_pipfile(package_name, dev)
if name and converted == '*':
# Skip for wildcard version
return
# Add the package to the group.
p[key][package_name] = package[package_name]
p[key][name or package_name] = package[package_name]
# Write Pipfile.
self.write_toml(p)
def add_index_to_pipfile(self, index):
"""Adds a given index to the Pipfile."""
# Read and append Pipfile.
p = self._pipfile
p = self.parsed_pipfile
source = {'url': index, 'verify_ssl': True}
# Add the package to the group.
if 'source' not in p:
@@ -650,7 +649,8 @@ class Project(object):
self.write_toml(p)
def recase_pipfile(self):
self.write_toml(recase_file(self._pipfile))
if self.ensure_proper_casing():
self.write_toml(self.parsed_pipfile)
def get_lockfile_hash(self):
if not os.path.exists(self.lockfile_location):
@@ -664,3 +664,38 @@ class Project(object):
# Update the lockfile if it is out-of-date.
p = pipfile.load(self.pipfile_location, inject_env=False)
return p.hash
def ensure_proper_casing(self):
"""Ensures proper casing of Pipfile packages"""
pfile = self.parsed_pipfile
casing_changed = self.proper_case_section(pfile.get('packages', {}))
casing_changed |= self.proper_case_section(pfile.get('dev-packages', {}))
return casing_changed
def proper_case_section(self, section):
"""Verify proper casing is retrieved, when available, for each
dependency in the section.
"""
# Casing for section.
changed_values = False
unknown_names = [
k for k in section.keys() if k not in set(self.proper_names)
]
# Replace each package with proper casing.
for dep in unknown_names:
try:
# Get new casing for package name.
new_casing = proper_case(dep)
except IOError:
# Unable to normalize package name.
continue
if new_casing != dep:
changed_values = True
self.register_proper_name(new_casing)
# Replace old value with new value.
old_value = section[dep]
section[new_casing] = old_value
del section[dep]
# Return whether or not values have been changed.
return changed_values
+52
View File
@@ -579,6 +579,58 @@ pytz = "*"
c = p.pipenv('run python -c "import six; import urllib3; import pytz;"')
assert c.return_code == 0
@pytest.mark.install
@pytest.mark.run
def test_normalize_name_install(self, pypi):
with PipenvInstance(pypi=pypi) as p:
with open(p.pipfile_path, 'w') as f:
contents = """
# Pre comment
[packages]
Requests = "==2.14.0" # Inline comment
"""
f.write(contents)
c = p.pipenv('install')
assert c.return_code == 0
c = p.pipenv('install requests')
assert c.return_code == 0
assert 'requests' not in p.pipfile['packages']
assert p.pipfile['packages']['Requests'] == '==2.14.0'
c = p.pipenv('install requests==2.18.4')
assert c.return_code == 0
assert p.pipfile['packages']['Requests'] == '==2.18.4'
c = p.pipenv('install python_DateUtil')
assert c.return_code == 0
assert 'python-dateutil' in p.pipfile['packages']
contents = open(p.pipfile_path).read()
assert '# Pre comment' in contents
assert '# Inline comment' in contents
@pytest.mark.uninstall
@pytest.mark.run
def test_normalize_name_uninstall(self, pypi):
with PipenvInstance(pypi=pypi) as p:
with open(p.pipfile_path, 'w') as f:
contents = """
# Pre comment
[packages]
Requests = "*"
python_DateUtil = "*" # Inline comment
"""
f.write(contents)
c = p.pipenv('install')
assert c.return_code == 0
c = p.pipenv('uninstall python_dateutil')
assert 'Requests' in p.pipfile['packages']
assert 'python_DateUtil' not in p.pipfile['packages']
contents = open(p.pipfile_path).read()
assert '# Pre comment' in contents
assert '# Inline comment' in contents
@pytest.mark.install
@pytest.mark.resolver
@pytest.mark.backup_resolver