Skip to content

Commit

Permalink
Merge pull request #1221 from uranusjr/windows-drive-casing
Browse files Browse the repository at this point in the history
Force Windows local drive names to uppercase
  • Loading branch information
kennethreitz committed Dec 19, 2017
2 parents c00cf9d + 4d24c5d commit f2d285a
Show file tree
Hide file tree
Showing 3 changed files with 49 additions and 7 deletions.
6 changes: 3 additions & 3 deletions pipenv/project.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
from .utils import (
mkdir_p, convert_deps_from_pip, pep423_name, recase_file,
find_requirements, is_file, is_vcs, python_version, cleanup_toml,
is_installable_file, is_valid_url
is_installable_file, is_valid_url, normalize_drive,
)
from .environments import PIPENV_MAX_DEPTH, PIPENV_VENV_IN_PROJECT
from .environments import PIPENV_VIRTUALENV, PIPENV_PIPFILE
Expand All @@ -23,7 +23,7 @@
if not os.path.isfile(PIPENV_PIPFILE):
raise RuntimeError('Given PIPENV_PIPFILE is not found!')
else:
PIPENV_PIPFILE = os.path.abspath(PIPENV_PIPFILE)
PIPENV_PIPFILE = normalize_drive(os.path.abspath(PIPENV_PIPFILE))


class Project(object):
Expand Down Expand Up @@ -224,7 +224,7 @@ def pipfile_location(self):
loc = pipfile.Pipfile.find(max_depth=PIPENV_MAX_DEPTH)
except RuntimeError:
loc = None
self._pipfile_location = loc
self._pipfile_location = normalize_drive(loc)

return self._pipfile_location

Expand Down
26 changes: 22 additions & 4 deletions pipenv/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -277,7 +277,7 @@ def get_requirement(dep):
remote URIs, and package names, and that we pass only valid requirement strings
to the requirements parser. Performs necessary modifications to requirements
object if the user input was a local relative path.
:param str dep: A requirement line
:returns: :class:`requirements.Requirement` object
"""
Expand Down Expand Up @@ -932,11 +932,11 @@ def proper_case(package_name):
def split_section(input_file, section_suffix, test_function):
"""
Split a pipfile or a lockfile section out by section name and test function
:param dict input_file: A dictionary containing either a pipfile or lockfile
:param str section_suffix: A string of the name of the section
:param func test_function: A test function to test against the value in the key/value pair
>>> split_section(my_lockfile, 'vcs', is_vcs)
{
'default': {
Expand Down Expand Up @@ -992,7 +992,7 @@ def merge_deps(file_dict, project, dev=False, requirements=False, ignore_hashes=
Given a file_dict, merges dependencies and converts them to pip dependency lists.
:param dict file_dict: The result of calling :func:`pipenv.utils.split_file`
:param :class:`pipenv.project.Project` project: Pipenv project
:param bool dev=False: Flag indicating whether dev dependencies are to be installed
:param bool dev=False: Flag indicating whether dev dependencies are to be installed
:param bool requirements=False: Flag indicating whether to use a requirements file
:param bool ignore_hashes=False:
:param bool blocking=False:
Expand Down Expand Up @@ -1174,3 +1174,21 @@ def touch_update_stamp():
except OSError:
with open(p, 'w') as fh:
fh.write('')


def normalize_drive(path):
"""Normalize drive in path so they stay consistent.
This currently only affects local drives on Windows, which can be
identified with either upper or lower cased drive names. The case is
always converted to uppercase because it seems to be preferred.
See: <https://github.com/pypa/pipenv/issues/1218>
"""
if os.name != 'nt':
return path
drive, tail = os.path.splitdrive(path)
# Only match (lower cased) local drives (e.g. 'c:'), not UNC mounts.
if drive.islower() and len(drive) == 2 and drive[1] == ':':
return '{}{}'.format(drive.upper(), tail)
return path
24 changes: 24 additions & 0 deletions tests/test_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -226,3 +226,27 @@ def test_new_line_end_of_toml_file(this):
new_toml = pipenv.utils.cleanup_toml(toml)
# testing if the end of the generated file contains a newline
assert new_toml[-1] == '\n'

@pytest.mark.parametrize('input_path, expected', [
('c:\\Program Files\\Python36\\python.exe',
'C:\\Program Files\\Python36\\python.exe'),
('C:\\Program Files\\Python36\\python.exe',
'C:\\Program Files\\Python36\\python.exe'),
('\\\\host\\share\\file.zip', '\\\\host\\share\\file.zip'),
('artifacts\\file.zip', 'artifacts\\file.zip'),
('.\\artifacts\\file.zip', '.\\artifacts\\file.zip'),
('..\\otherproject\\file.zip', '..\\otherproject\\file.zip'),
])
@pytest.mark.skipif(os.name != 'nt', reason='Windows file paths tested')
def test_win_normalize_drive(self, input_path, expected):
assert pipenv.utils.normalize_drive(input_path) == expected

@pytest.mark.parametrize('input_path, expected', [
('/usr/local/bin/python', '/usr/local/bin/python'),
('artifacts/file.zip', 'artifacts/file.zip'),
('./artifacts/file.zip', './artifacts/file.zip'),
('../otherproject/file.zip', '../otherproject/file.zip'),
])
@pytest.mark.skipif(os.name == 'nt', reason='*nix file paths tested')
def test_nix_normalize_drive(self, input_path, expected):
assert pipenv.utils.normalize_drive(input_path) == expected

0 comments on commit f2d285a

Please sign in to comment.