mirror of
https://github.com/kennethreitz/pipenv.git
synced 2026-06-05 22:50:18 +00:00
Merge branch 'master' into test-fixes
This commit is contained in:
+5
-43
@@ -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
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user