Default to \n, retain consistent \r\n

When writing the Pipfile and Pipfile.lock make an effort to retain
their existing newlines if consistent.  Default to \n (LF) for new
files and files with inconsistent line endings.
This commit is contained in:
Kyle Altendorf
2018-04-26 15:50:36 -04:00
parent d2eeac7729
commit 6d2e208aae
4 changed files with 96 additions and 28 deletions
+1 -7
View File
@@ -1166,13 +1166,7 @@ def do_lock(
default_package
]
if write:
# Write out the lockfile.
with open(project.lockfile_location, 'w') as f:
simplejson.dump(
lockfile, f, indent=4, separators=(',', ': '), sort_keys=True
)
# Write newline at end of document. GH Issue #319.
f.write('\n')
project.write_lockfile(lockfile)
click.echo(
'{0}'.format(
crayons.normal(
+56 -20
View File
@@ -1,5 +1,6 @@
# -*- coding: utf-8 -*-
import codecs
import io
import json
import os
import re
@@ -11,6 +12,7 @@ from first import first
import pipfile
import pipfile.api
import toml
import json as simplejson
try:
import pathlib
@@ -49,6 +51,16 @@ def _normalized(p):
return normalize_drive(str(pathlib.Path(p).resolve()))
DEFAULT_NEWLINES = u'\n'
def preferred_newlines(f):
if isinstance(f.newlines, type(u'')):
return f.newlines
return DEFAULT_NEWLINES
if PIPENV_PIPFILE:
if not os.path.isfile(PIPENV_PIPFILE):
raise RuntimeError('Given PIPENV_PIPFILE is not found!')
@@ -90,6 +102,8 @@ class Project(object):
self._download_location = None
self._proper_names_location = None
self._pipfile_location = None
self._pipfile_newlines = DEFAULT_NEWLINES
self._lockfile_newlines = DEFAULT_NEWLINES
self._requirements_location = None
self._original_dir = os.path.abspath(os.curdir)
self.which = which
@@ -369,9 +383,7 @@ class Project(object):
"""Parse Pipfile into a TOMLFile and cache it
(call clear_pipfile_cache() afterwards if mutating)"""
# Open the pipfile, read it into memory.
with open(self.pipfile_location) as f:
contents = f.read()
contents = self.read_pipfile()
# use full contents to get around str/bytes 2/3 issues
cache_key = (self.pipfile_location, contents)
if cache_key not in _pipfile_cache:
@@ -379,10 +391,17 @@ class Project(object):
_pipfile_cache[cache_key] = parsed
return _pipfile_cache[cache_key]
def read_pipfile(self):
# Open the pipfile, read it into memory.
with io.open(self.pipfile_location) as f:
contents = f.read()
self._pipfile_newlines = preferred_newlines(f)
return contents
@property
def pased_pure_pipfile(self):
with open(self.pipfile_location) as f:
contents = f.read()
contents = self.read_pipfile()
return self._parse_pipfile(contents)
@@ -474,14 +493,7 @@ class Project(object):
@property
def lockfile_content(self):
with open(self.lockfile_location) as 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
return self.load_lockfile()
@property
def editable_packages(self):
@@ -546,9 +558,8 @@ class Project(object):
if not self.pipfile_exists:
return True
with open(self.pipfile_location, 'r') as f:
if not f.read():
return True
if not len(self.read_pipfile()):
return True
return False
@@ -609,12 +620,26 @@ class Project(object):
)
data[section][package].update(_data)
formatted_data = toml.dumps(data).rstrip()
if os.path.abspath(path) == os.path.abspath(self.pipfile_location):
newlines = self._pipfile_newlines
else:
newlines = preferred_newlines()
formatted_data = cleanup_toml(formatted_data)
with open(path, 'w') as f:
with io.open(path, 'w', newline=newlines) as f:
f.write(formatted_data)
# pipfile is mutated!
self.clear_pipfile_cache()
def write_lockfile(self, content):
# Write out the lockfile.
newlines = self._lockfile_newlines
with open(self.lockfile_location, 'w', newline=newlines) as f:
simplejson.dump(
content, f, indent=4, separators=(',', ': '), sort_keys=True
)
# Write newline at end of document. GH Issue #319.
f.write('\n')
@property
def pipfile_sources(self):
if 'source' in self.parsed_pipfile:
@@ -742,12 +767,23 @@ class Project(object):
if self.ensure_proper_casing():
self.write_toml(self.parsed_pipfile)
def load_lockfile(self, expand_env_vars=True):
with io.open(self.lockfile_location) as lock:
j = json.load(lock)
self._lockfile_newlines = preferred_newlines(lock)
if expand_env_vars:
# 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
def get_lockfile_hash(self):
if not os.path.exists(self.lockfile_location):
return
# Open the lockfile.
with codecs.open(self.lockfile_location, 'r') as f:
lockfile = json.load(f)
lockfile = self.load_lockfile(expand_env_vars=False)
return lockfile['_meta'].get('hash', {}).get('sha256')
def calculate_pipfile_hash(self):
+5 -1
View File
@@ -113,10 +113,14 @@ class _PipenvInstance(object):
@property
def lockfile(self):
p_path = os.sep.join([self.path, 'Pipfile.lock'])
p_path = self.lockfile_path
with open(p_path, 'r') as f:
return json.loads(f.read())
@property
def lockfile_path(self):
return os.sep.join([self.path, 'Pipfile.lock'])
@pytest.fixture()
def PipenvInstance():
+34
View File
@@ -1,4 +1,5 @@
# -*- coding=utf-8 -*-
import io
import pytest
import os
from pipenv.project import Project
@@ -73,3 +74,36 @@ six = {{version = "*", index = "pypi"}}
assert sorted(source.items()) == sorted(project.get_source(url=url).items())
assert sorted(source.items()) == sorted(project.find_source(name).items())
assert sorted(source.items()) == sorted(project.find_source(url).items())
@pytest.mark.install
@pytest.mark.project
@pytest.mark.parametrize('newlines', [u'\n', u'\r\n'])
@pytest.mark.parametrize('target', ['pipfile_path', 'lockfile_path'])
def test_maintain_file_line_endings(PipenvInstance, pypi, newlines, target):
with PipenvInstance(pypi=pypi, chdir=True) as p:
path = getattr(p, target)
c = p.pipenv('install')
assert c.return_code == 0
with io.open(path) as f:
contents = f.read()
assert f.newlines == u'\n'
with io.open(path, 'w', newline=newlines) as f:
f.write(contents)
before = os.path.getmtime(path)
c = p.pipenv('install chardet')
assert c.return_code == 0
assert os.path.getmtime(path) != before
with io.open(path) as f:
f.read()
actual_newlines = f.newlines
assert actual_newlines == newlines