mirror of
https://github.com/kennethreitz/pipenv.git
synced 2026-06-05 22:50:18 +00:00
Merge branch 'master' into pew-associate-project-dir
This commit is contained in:
@@ -2,4 +2,4 @@
|
||||
# // ) ) / / // ) ) //___) ) // ) ) || / /
|
||||
# //___/ / / / //___/ / // // / / || / /
|
||||
# // / / // ((____ // / / ||/ /
|
||||
__version__ = '11.10.1'
|
||||
__version__ = '11.10.2.dev1'
|
||||
|
||||
+2
-3
@@ -9,7 +9,7 @@ import io
|
||||
import os
|
||||
import six
|
||||
import warnings
|
||||
from tempfile import _bin_openflags, gettempdir, _mkstemp_inner, mkdtemp, _text_openflags
|
||||
from tempfile import _bin_openflags, gettempdir, _mkstemp_inner, mkdtemp
|
||||
from .utils import (logging, rmtree)
|
||||
|
||||
try:
|
||||
@@ -258,13 +258,12 @@ def NamedTemporaryFile(
|
||||
if os.name == "nt" and delete:
|
||||
flags |= os.O_TEMPORARY
|
||||
if six.PY2:
|
||||
flags = _text_openflags if 'b' not in mode else flags
|
||||
(fd, name) = _mkstemp_inner(dir, prefix, suffix, flags)
|
||||
else:
|
||||
(fd, name) = _mkstemp_inner(dir, prefix, suffix, flags, output_type)
|
||||
try:
|
||||
file = io.open(
|
||||
fd, mode, buffering=buffering, newline=newline, encoding=encoding
|
||||
fd, mode, buffering=buffering, newline=newline, encoding=encoding,
|
||||
)
|
||||
return _TemporaryFileWrapper(file, name, delete)
|
||||
|
||||
|
||||
+18
-14
@@ -25,7 +25,6 @@ import six
|
||||
from .cmdparse import ScriptEmptyError
|
||||
from .project import Project, SourceNotFound
|
||||
from .utils import (
|
||||
atomic_open_for_write,
|
||||
convert_deps_from_pip,
|
||||
convert_deps_to_pip,
|
||||
is_required_version,
|
||||
@@ -1168,13 +1167,7 @@ def do_lock(
|
||||
default_package
|
||||
]
|
||||
if write:
|
||||
# Write out the lockfile.
|
||||
with atomic_open_for_write(project.lockfile_location) 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(
|
||||
@@ -2494,19 +2487,30 @@ def do_sync(
|
||||
unused=False,
|
||||
sequential=False,
|
||||
):
|
||||
# The lock file needs to exist because sync won't write to it.
|
||||
if not project.lockfile_exists:
|
||||
click.echo(
|
||||
'{0}: Pipfile.lock is missing! You need to run {1} first.'.format(
|
||||
crayons.red('Error', bold=True),
|
||||
crayons.red('$ pipenv lock', bold=True),
|
||||
),
|
||||
err=True,
|
||||
)
|
||||
sys.exit(1)
|
||||
|
||||
# Ensure that virtualenv is available.
|
||||
ensure_project(three=three, python=python, validate=False)
|
||||
|
||||
# Install everything.
|
||||
requirements_dir = TemporaryDirectory(
|
||||
suffix='-requirements', prefix='pipenv-'
|
||||
)
|
||||
# Ensure that virtualenv is available.
|
||||
ensure_project(three=three, python=python, validate=False)
|
||||
concurrent = (not sequential)
|
||||
ensure_lockfile()
|
||||
# Install everything.
|
||||
do_init(
|
||||
dev=dev,
|
||||
verbose=verbose,
|
||||
concurrent=concurrent,
|
||||
concurrent=(not sequential),
|
||||
requirements_dir=requirements_dir,
|
||||
ignore_pipfile=True, # Don't check if Pipfile and lock match.
|
||||
)
|
||||
requirements_dir.cleanup()
|
||||
click.echo(crayons.green('All dependencies are now up-to-date!'))
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
Copyright 2016 Kenneth Reitz
|
||||
Copyright 2017 Kenneth Reitz
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
setuptools==39.1.0
|
||||
appdirs==1.4.0
|
||||
distlib==0.2.4
|
||||
distro==1.2.0
|
||||
html5lib==1.0b10
|
||||
six==1.10.0
|
||||
colorama==0.3.7
|
||||
requests==2.18.4
|
||||
chardet==3.0.4
|
||||
idna==2.6
|
||||
urllib3==1.22
|
||||
certifi==2018.1.18
|
||||
CacheControl==0.11.7
|
||||
lockfile==0.12.2
|
||||
ordereddict==1.1
|
||||
progress==1.2
|
||||
ipaddress==1.0.17
|
||||
packaging==16.8
|
||||
pyparsing==2.1.10
|
||||
retrying==1.3.3
|
||||
webencodings==0.5
|
||||
+73
-27
@@ -1,5 +1,5 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
import codecs
|
||||
import io
|
||||
import json
|
||||
import os
|
||||
import re
|
||||
@@ -10,15 +10,18 @@ import contoml
|
||||
from first import first
|
||||
import pipfile
|
||||
import pipfile.api
|
||||
import six
|
||||
import toml
|
||||
import json as simplejson
|
||||
|
||||
try:
|
||||
import pathlib
|
||||
from pathlib import Path
|
||||
except ImportError:
|
||||
import pathlib2 as pathlib
|
||||
from pathlib2 import Path
|
||||
|
||||
from .cmdparse import Script
|
||||
from .utils import (
|
||||
atomic_open_for_write,
|
||||
mkdir_p,
|
||||
pep423_name,
|
||||
proper_case,
|
||||
@@ -46,7 +49,17 @@ from .environments import (
|
||||
def _normalized(p):
|
||||
if p is None:
|
||||
return None
|
||||
return normalize_drive(str(pathlib.Path(p).resolve()))
|
||||
return normalize_drive(str(Path(p).resolve()))
|
||||
|
||||
|
||||
DEFAULT_NEWLINES = u'\n'
|
||||
|
||||
|
||||
def preferred_newlines(f):
|
||||
if isinstance(f.newlines, six.text_type):
|
||||
return f.newlines
|
||||
|
||||
return DEFAULT_NEWLINES
|
||||
|
||||
|
||||
if PIPENV_PIPFILE:
|
||||
@@ -90,6 +103,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 +384,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 +392,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 +494,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 +559,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
|
||||
|
||||
@@ -572,7 +584,7 @@ class Project(object):
|
||||
u'name': source_name,
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
data = {
|
||||
u'source': sources,
|
||||
# Default packages.
|
||||
@@ -610,12 +622,29 @@ class Project(object):
|
||||
)
|
||||
data[section][package].update(_data)
|
||||
formatted_data = toml.dumps(data).rstrip()
|
||||
|
||||
if Path(path).absolute() == Path(self.pipfile_location).absolute():
|
||||
newlines = self._pipfile_newlines
|
||||
else:
|
||||
newlines = DEFAULT_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
|
||||
s = simplejson.dumps( # Send Unicode in to guarentee Unicode out.
|
||||
content, indent=4, separators=(u',', u': '), sort_keys=True,
|
||||
)
|
||||
with atomic_open_for_write(self.lockfile_location, newline=newlines) as f:
|
||||
f.write(s)
|
||||
if not s.endswith(u'\n'):
|
||||
f.write(u'\n') # Write newline at end of document. GH #319.
|
||||
|
||||
@property
|
||||
def pipfile_sources(self):
|
||||
if 'source' in self.parsed_pipfile:
|
||||
@@ -632,7 +661,7 @@ class Project(object):
|
||||
|
||||
@property
|
||||
def sources(self):
|
||||
if self.lockfile_exists:
|
||||
if self.lockfile_exists and hasattr(self.lockfile_content, 'keys'):
|
||||
meta_ = self.lockfile_content['_meta']
|
||||
sources_ = meta_.get('sources')
|
||||
if sources_:
|
||||
@@ -735,13 +764,30 @@ 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)
|
||||
# lockfile is just a string
|
||||
if not j or not hasattr(j, 'keys'):
|
||||
return j
|
||||
|
||||
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)
|
||||
return lockfile['_meta'].get('hash', {}).get('sha256')
|
||||
|
||||
lockfile = self.load_lockfile(expand_env_vars=False)
|
||||
if '_meta' in lockfile and hasattr(lockfile, 'keys'):
|
||||
return lockfile['_meta'].get('hash', {}).get('sha256')
|
||||
# Lockfile exists but has no hash at all
|
||||
return ''
|
||||
|
||||
def calculate_pipfile_hash(self):
|
||||
# Update the lockfile if it is out-of-date.
|
||||
|
||||
+12
-4
@@ -657,6 +657,7 @@ def convert_deps_to_pip(deps, project=None, r=True, include_index=False):
|
||||
for dep in deps.keys():
|
||||
# Default (e.g. '>1.10').
|
||||
extra = deps[dep] if isinstance(deps[dep], six.string_types) else ''
|
||||
extras = ''
|
||||
version = ''
|
||||
index = ''
|
||||
# Get rid of '*'.
|
||||
@@ -675,7 +676,7 @@ def convert_deps_to_pip(deps, project=None, r=True, include_index=False):
|
||||
)
|
||||
# Support for extras (e.g. requests[socks])
|
||||
if 'extras' in deps[dep]:
|
||||
extra = '[{0}]'.format(','.join(deps[dep]['extras']))
|
||||
extras = '[{0}]'.format(','.join(deps[dep]['extras']))
|
||||
if 'version' in deps[dep]:
|
||||
if not is_star(deps[dep]['version']):
|
||||
version = deps[dep]['version']
|
||||
@@ -709,9 +710,14 @@ def convert_deps_to_pip(deps, project=None, r=True, include_index=False):
|
||||
# Support for version control
|
||||
maybe_vcs = [vcs for vcs in VCS_LIST if vcs in deps[dep]]
|
||||
vcs = maybe_vcs[0] if maybe_vcs else None
|
||||
if not any(key in deps[dep] for key in ['path', 'vcs', 'file']):
|
||||
extra += extras
|
||||
# Support for files.
|
||||
if 'file' in deps[dep]:
|
||||
extra = '{1}{0}'.format(extra, deps[dep]['file']).strip()
|
||||
dep_file = deps[dep]['file']
|
||||
if is_valid_url(dep_file) and dep_file.startswith('http'):
|
||||
dep_file += '#egg={0}'.format(dep)
|
||||
extra = '{0}{1}'.format(dep_file, extras).strip()
|
||||
# Flag the file as editable if it is a local relative path
|
||||
if 'editable' in deps[dep]:
|
||||
dep = '-e '
|
||||
@@ -719,7 +725,7 @@ def convert_deps_to_pip(deps, project=None, r=True, include_index=False):
|
||||
dep = ''
|
||||
# Support for paths.
|
||||
elif 'path' in deps[dep]:
|
||||
extra = '{1}{0}'.format(extra, deps[dep]['path']).strip()
|
||||
extra = '{1}{0}'.format(extras, deps[dep]['path']).strip()
|
||||
# Flag the file as editable if it is a local relative path
|
||||
if 'editable' in deps[dep]:
|
||||
dep = '-e '
|
||||
@@ -730,7 +736,7 @@ def convert_deps_to_pip(deps, project=None, r=True, include_index=False):
|
||||
# Support for @refs.
|
||||
if 'ref' in deps[dep]:
|
||||
extra += '@{0}'.format(deps[dep]['ref'])
|
||||
extra += '#egg={0}'.format(dep)
|
||||
extra += '#egg={0}{1}'.format(dep, extras)
|
||||
# Support for subdirectory
|
||||
if 'subdirectory' in deps[dep]:
|
||||
extra += '&subdirectory={0}'.format(deps[dep]['subdirectory'])
|
||||
@@ -740,6 +746,7 @@ def convert_deps_to_pip(deps, project=None, r=True, include_index=False):
|
||||
dep = '-e '
|
||||
else:
|
||||
dep = ''
|
||||
|
||||
s = '{0}{1}{2}{3}{4} {5}'.format(
|
||||
dep, extra, version, specs, hash, index
|
||||
).strip()
|
||||
@@ -1305,6 +1312,7 @@ def atomic_open_for_write(target, binary=False, newline=None, encoding=None):
|
||||
target with this new file.
|
||||
"""
|
||||
from ._compat import NamedTemporaryFile
|
||||
|
||||
mode = 'w+b' if binary else 'w'
|
||||
f = NamedTemporaryFile(
|
||||
dir=os.path.dirname(target),
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
Copyright 2016 Kenneth Reitz
|
||||
Copyright 2017 Kenneth Reitz
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
|
||||
+21
@@ -0,0 +1,21 @@
|
||||
setuptools==39.1.0
|
||||
appdirs==1.4.0
|
||||
distlib==0.2.4
|
||||
distro==1.2.0
|
||||
html5lib==1.0b10
|
||||
six==1.10.0
|
||||
colorama==0.3.7
|
||||
requests==2.18.4
|
||||
chardet==3.0.4
|
||||
idna==2.6
|
||||
urllib3==1.22
|
||||
certifi==2018.1.18
|
||||
CacheControl==0.11.7
|
||||
lockfile==0.12.2
|
||||
ordereddict==1.1
|
||||
progress==1.2
|
||||
ipaddress==1.0.17
|
||||
packaging==16.8
|
||||
pyparsing==2.1.10
|
||||
retrying==1.3.3
|
||||
webencodings==0.5
|
||||
Vendored
+21
@@ -0,0 +1,21 @@
|
||||
setuptools==39.1.0
|
||||
appdirs==1.4.0
|
||||
distlib==0.2.4
|
||||
distro==1.2.0
|
||||
html5lib==1.0b10
|
||||
six==1.10.0
|
||||
colorama==0.3.7
|
||||
requests==2.18.4
|
||||
chardet==3.0.4
|
||||
idna==2.6
|
||||
urllib3==1.22
|
||||
certifi==2018.1.18
|
||||
CacheControl==0.11.7
|
||||
lockfile==0.12.2
|
||||
ordereddict==1.1
|
||||
progress==1.2
|
||||
ipaddress==1.0.17
|
||||
packaging==16.8
|
||||
pyparsing==2.1.10
|
||||
retrying==1.3.3
|
||||
webencodings==0.5
|
||||
+36
-64
@@ -17,13 +17,14 @@ import requests
|
||||
|
||||
TASK_NAME = 'update'
|
||||
|
||||
LIBRARY_OVERRIDES = {
|
||||
LIBRARY_DIRNAMES = {
|
||||
'requirements-parser': 'requirements',
|
||||
'backports.shutil_get_terminal_size': 'backports/shutil_get_terminal_size',
|
||||
'backports.weakref': 'backports/weakref',
|
||||
'shutil_backports': 'backports/shutil_get_terminal_size',
|
||||
'python-dotenv': 'dotenv',
|
||||
'pip-tools': 'piptools'
|
||||
'pip-tools': 'piptools',
|
||||
'setuptools': 'pkg_resources',
|
||||
}
|
||||
|
||||
# from time to time, remove the no longer needed ones
|
||||
@@ -38,7 +39,10 @@ HARDCODED_LICENSE_URLS = {
|
||||
'semver': 'https://raw.githubusercontent.com/k-bx/python-semver/master/LICENSE.txt',
|
||||
'crayons': 'https://raw.githubusercontent.com/kennethreitz/crayons/master/LICENSE',
|
||||
'pip-tools': 'https://raw.githubusercontent.com/jazzband/pip-tools/master/LICENSE',
|
||||
'pew': 'https://raw.githubusercontent.com/berdario/pew/master/LICENSE'
|
||||
'pew': 'https://raw.githubusercontent.com/berdario/pew/master/LICENSE',
|
||||
'pytoml': 'https://github.com/avakar/pytoml/raw/master/LICENSE',
|
||||
'webencodings': 'https://github.com/SimonSapin/python-webencodings/raw/'
|
||||
'master/LICENSE',
|
||||
}
|
||||
|
||||
FILE_WHITE_LIST = (
|
||||
@@ -50,7 +54,8 @@ FILE_WHITE_LIST = (
|
||||
'README.md',
|
||||
'appdirs.py',
|
||||
'safety.zip',
|
||||
'cacert.pem'
|
||||
'cacert.pem',
|
||||
'vendor_pip.txt',
|
||||
)
|
||||
|
||||
LIBRARY_RENAMES = {
|
||||
@@ -212,14 +217,6 @@ cli(prog_name="safety")
|
||||
else:
|
||||
lib = yaml_build_dir / 'lib3' / 'yaml'
|
||||
shutil.copytree(str(lib.absolute()), str(safety_dir / 'yaml{0}'.format(version_choices[0])))
|
||||
# yaml_init = yaml_dir / '__init__.py'
|
||||
# yaml_init.write_text("""
|
||||
# import sys
|
||||
# if sys.version_info[0] == 3:
|
||||
# from .yaml3 import *
|
||||
# else:
|
||||
# from .yaml2 import *
|
||||
# """.strip())
|
||||
requests_dir = safety_dir / 'requests'
|
||||
cacert = vendor_dir / 'requests' / 'cacert.pem'
|
||||
if not cacert.exists():
|
||||
@@ -247,8 +244,8 @@ cli(prog_name="safety")
|
||||
def rename_if_needed(ctx, vendor_dir, item):
|
||||
rename_dict = LIBRARY_RENAMES if vendor_dir.name != 'patched' else PATCHED_RENAMES
|
||||
new_path = None
|
||||
if item.name in rename_dict or item.name in LIBRARY_OVERRIDES:
|
||||
new_name = rename_dict.get(item.name, LIBRARY_OVERRIDES.get(item.name))
|
||||
if item.name in rename_dict or item.name in LIBRARY_DIRNAMES:
|
||||
new_name = rename_dict.get(item.name, LIBRARY_DIRNAMES.get(item.name))
|
||||
new_path = item.parent / new_name
|
||||
log('Renaming %s => %s' % (item.name, new_path))
|
||||
# handle existing directories
|
||||
@@ -307,7 +304,6 @@ def vendor(ctx, vendor_dir, rewrite=True):
|
||||
apply_patch(ctx, patch)
|
||||
|
||||
# Global import rewrites
|
||||
# log("Rewriting all imports related to vendored libs")
|
||||
log('Renaming specified libs...')
|
||||
for item in vendor_dir.iterdir():
|
||||
if item.is_dir():
|
||||
@@ -401,16 +397,17 @@ def find_and_extract_license(vendor_dir, tar, members):
|
||||
|
||||
def license_fallback(vendor_dir, sdist_name):
|
||||
"""Hardcoded license URLs. Check when updating if those are still needed"""
|
||||
for libname, url in HARDCODED_LICENSE_URLS.items():
|
||||
if libname in sdist_name:
|
||||
_, _, name = url.rpartition('/')
|
||||
dest = license_destination(vendor_dir, libname, name)
|
||||
r = requests.get(url, allow_redirects=True)
|
||||
log('Downloading {}'.format(url))
|
||||
r.raise_for_status()
|
||||
dest.write_bytes(r.content)
|
||||
return
|
||||
raise ValueError('No hardcoded URL for {} license'.format(sdist_name))
|
||||
libname = libname_from_dir(sdist_name)
|
||||
if libname not in HARDCODED_LICENSE_URLS:
|
||||
raise ValueError('No hardcoded URL for {} license'.format(libname))
|
||||
|
||||
url = HARDCODED_LICENSE_URLS[libname]
|
||||
_, _, name = url.rpartition('/')
|
||||
dest = license_destination(vendor_dir, libname, name)
|
||||
r = requests.get(url, allow_redirects=True)
|
||||
log('Downloading {}'.format(url))
|
||||
r.raise_for_status()
|
||||
dest.write_bytes(r.content)
|
||||
|
||||
|
||||
def libname_from_dir(dirname):
|
||||
@@ -420,7 +417,7 @@ def libname_from_dir(dirname):
|
||||
if part[0].isdigit():
|
||||
break
|
||||
parts.append(part)
|
||||
return'-'.join(parts)
|
||||
return '-'.join(parts)
|
||||
|
||||
|
||||
def license_destination(vendor_dir, libname, filename):
|
||||
@@ -432,16 +429,17 @@ def license_destination(vendor_dir, libname, filename):
|
||||
if lowercase.is_dir():
|
||||
return lowercase / filename
|
||||
rename_dict = LIBRARY_RENAMES if vendor_dir.name != 'patched' else PATCHED_RENAMES
|
||||
# Short circuit all logic if we are renaming the whole library
|
||||
if libname in rename_dict:
|
||||
return vendor_dir / rename_dict[libname] / filename
|
||||
if libname in LIBRARY_OVERRIDES:
|
||||
override = vendor_dir / LIBRARY_OVERRIDES[libname]
|
||||
if libname in LIBRARY_DIRNAMES:
|
||||
override = vendor_dir / LIBRARY_DIRNAMES[libname]
|
||||
if not override.exists() and override.parent.exists():
|
||||
# for flattened subdeps, specifically backports/weakref.py
|
||||
target_dir = vendor_dir / override.parent
|
||||
target_file = '{0}.{1}'.format(override.name, filename)
|
||||
return target_dir / target_file
|
||||
return vendor_dir / LIBRARY_OVERRIDES[libname] / filename
|
||||
return (
|
||||
vendor_dir / override.parent
|
||||
) / '{0}.{1}'.format(override.name, filename)
|
||||
return vendor_dir / LIBRARY_DIRNAMES[libname] / filename
|
||||
# fallback to libname.LICENSE (used for nondirs)
|
||||
return vendor_dir / '{}.{}'.format(libname, filename)
|
||||
|
||||
@@ -451,8 +449,6 @@ def extract_license_member(vendor_dir, tar, member, name):
|
||||
dirname = list(mpath.parents)[-2].name # -1 is .
|
||||
libname = libname_from_dir(dirname)
|
||||
dest = license_destination(vendor_dir, libname, mpath.name)
|
||||
# dest_relative = dest.relative_to(Path.cwd())
|
||||
# log('Extracting {} into {}'.format(name, dest_relative))
|
||||
log('Extracting {} into {}'.format(name, dest))
|
||||
try:
|
||||
fileobj = tar.extractfile(member)
|
||||
@@ -461,36 +457,6 @@ def extract_license_member(vendor_dir, tar, member, name):
|
||||
dest.write_bytes(tar.read(member))
|
||||
|
||||
|
||||
@invoke.task
|
||||
def update_stubs(ctx):
|
||||
vendor_dir = _get_vendor_dir(ctx)
|
||||
vendored_libs = detect_vendored_libs(vendor_dir)
|
||||
|
||||
print("[vendoring.update_stubs] Add mypy stubs")
|
||||
|
||||
extra_stubs_needed = {
|
||||
# Some projects need stubs other than a simple <name>.pyi
|
||||
"six": ["six.__init__", "six.moves"],
|
||||
# Some projects should not have stubs coz they're single file modules
|
||||
"appdirs": [],
|
||||
}
|
||||
|
||||
for lib in vendored_libs:
|
||||
if lib not in extra_stubs_needed:
|
||||
(vendor_dir / (lib + ".pyi")).write_text("from %s import *" % lib)
|
||||
continue
|
||||
|
||||
for selector in extra_stubs_needed[lib]:
|
||||
fname = selector.replace(".", os.sep) + ".pyi"
|
||||
if selector.endswith(".__init__"):
|
||||
selector = selector[:-9]
|
||||
|
||||
f_path = vendor_dir / fname
|
||||
if not f_path.parent.exists():
|
||||
f_path.parent.mkdir()
|
||||
f_path.write_text("from %s import *" % selector)
|
||||
|
||||
|
||||
@invoke.task(name=TASK_NAME)
|
||||
def main(ctx):
|
||||
vendor_dir = _get_vendor_dir(ctx)
|
||||
@@ -502,5 +468,11 @@ def main(ctx):
|
||||
vendor(ctx, patched_dir, rewrite=False)
|
||||
download_licenses(ctx, vendor_dir)
|
||||
download_licenses(ctx, patched_dir, 'patched.txt')
|
||||
for pip_dir in [vendor_dir / 'pip9', patched_dir / 'notpip']:
|
||||
_vendor_dir = pip_dir / '_vendor'
|
||||
vendor_src_file = vendor_dir / 'vendor_pip.txt'
|
||||
vendor_file = _vendor_dir / 'vendor.txt'
|
||||
vendor_file.write_bytes(vendor_src_file.read_bytes())
|
||||
download_licenses(ctx, _vendor_dir)
|
||||
# update_safety(ctx)
|
||||
log('Revendoring complete')
|
||||
|
||||
@@ -55,3 +55,14 @@ index 48aaa35..bf1cba9 100644
|
||||
|
||||
url:
|
||||
url of the resource pointed to (href of the link)
|
||||
|
||||
diff --git a/pipenv/patched/notpip/models/index.py b/pipenv/patched/notpip/models/index.py
|
||||
index 25fd488d..db324287 100644
|
||||
--- a/pipenv/patched/notpip/models/index.py
|
||||
+++ b/pipenv/patched/notpip/models/index.py
|
||||
@@ -13,4 +13,4 @@ class Index(object):
|
||||
return urllib_parse.urljoin(self.url, path)
|
||||
|
||||
|
||||
-PyPI = Index('https://pypi.python.org/')
|
||||
+PyPI = Index('https://pypi.org/')
|
||||
|
||||
@@ -1,13 +0,0 @@
|
||||
diff --git a/pipenv/patched/pipfile/api.py b/pipenv/patched/pipfile/api.py
|
||||
index 18a1ea2..e8fa027 100644
|
||||
--- a/pipenv/patched/pipfile/api.py
|
||||
+++ b/pipenv/patched/pipfile/api.py
|
||||
@@ -10,7 +10,7 @@ import os
|
||||
|
||||
|
||||
DEFAULT_SOURCE = {
|
||||
- u'url': u'https://pypi.python.org/simple',
|
||||
+ u'url': u'https://pypi.org/simple',
|
||||
u'verify_ssl': True,
|
||||
u'name': u'pypi',
|
||||
}
|
||||
@@ -12,7 +12,7 @@ index 8a2a6a3..18a1ea2 100644
|
||||
|
||||
|
||||
+DEFAULT_SOURCE = {
|
||||
+ u'url': u'https://pypi.python.org/simple',
|
||||
+ u'url': u'https://pypi.org/simple',
|
||||
+ u'verify_ssl': True,
|
||||
+ u'name': u'pypi',
|
||||
+}
|
||||
|
||||
@@ -85,7 +85,8 @@ index d3b7fe7..e1f63d2 100644
|
||||
+
|
||||
+
|
||||
class PyPIRepository(BaseRepository):
|
||||
DEFAULT_INDEX_URL = 'https://pypi.python.org/simple'
|
||||
- DEFAULT_INDEX_URL = 'https://pypi.python.org/simple'
|
||||
+ DEFAULT_INDEX_URL = 'https://pypi.org/simple'
|
||||
|
||||
@@ -30,8 +69,9 @@ class PyPIRepository(BaseRepository):
|
||||
config), but any other PyPI mirror can be used if index_urls is
|
||||
|
||||
@@ -10,19 +10,20 @@ index 59fd5748..48663aed 100644
|
||||
+
|
||||
from prettytoml.elements.common import ContainerElement
|
||||
from prettytoml.elements import traversal
|
||||
|
||||
|
||||
|
||||
|
||||
-class AbstractTable(ContainerElement, traversal.TraversalMixin):
|
||||
+class AbstractTable(ContainerElement, traversal.TraversalMixin, Mapping):
|
||||
"""
|
||||
Common code for handling tables as key-value pairs with metadata elements sprinkled all over.
|
||||
|
||||
|
||||
@@ -37,6 +42,9 @@ class AbstractTable(ContainerElement, traversal.TraversalMixin):
|
||||
def __len__(self):
|
||||
return len(tuple(self._enumerate_items()))
|
||||
|
||||
|
||||
+ def __iter__(self):
|
||||
+ return (key for key, _ in self.items())
|
||||
+
|
||||
def __contains__(self, item):
|
||||
return item in self.keys()
|
||||
|
||||
|
||||
@@ -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():
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
# -*- coding=utf-8 -*-
|
||||
import io
|
||||
import pytest
|
||||
import os
|
||||
from pipenv.project import Project
|
||||
@@ -73,3 +74,40 @@ 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'])
|
||||
def test_maintain_file_line_endings(PipenvInstance, pypi, newlines):
|
||||
with PipenvInstance(pypi=pypi, chdir=True) as p:
|
||||
# Initial pipfile + lockfile generation
|
||||
c = p.pipenv('install pytz')
|
||||
assert c.return_code == 0
|
||||
|
||||
# Rewrite each file with parameterized newlines
|
||||
for fn in [p.pipfile_path, p.lockfile_path]:
|
||||
with io.open(fn) as f:
|
||||
contents = f.read()
|
||||
written_newlines = f.newlines
|
||||
|
||||
assert written_newlines == u'\n', '{0!r} != {1!r} for {2}'.format(
|
||||
written_newlines, u'\n', fn,
|
||||
)
|
||||
# message because of https://github.com/pytest-dev/pytest/issues/3443
|
||||
with io.open(fn, 'w', newline=newlines) as f:
|
||||
f.write(contents)
|
||||
|
||||
# Run pipenv install to programatically rewrite
|
||||
c = p.pipenv('install chardet')
|
||||
assert c.return_code == 0
|
||||
|
||||
# Make sure we kept the right newlines
|
||||
for fn in [p.pipfile_path, p.lockfile_path]:
|
||||
with io.open(fn) as f:
|
||||
f.read() # Consumes the content to detect newlines.
|
||||
actual_newlines = f.newlines
|
||||
assert actual_newlines == newlines, '{0!r} != {1!r} for {2}'.format(
|
||||
actual_newlines, newlines, fn,
|
||||
)
|
||||
# message because of https://github.com/pytest-dev/pytest/issues/3443
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
import pytest
|
||||
|
||||
|
||||
@pytest.mark.sync
|
||||
def test_sync_error_without_lockfile(PipenvInstance, pypi):
|
||||
with PipenvInstance(pypi=pypi) as p:
|
||||
with open(p.pipfile_path, 'w') as f:
|
||||
f.write("""
|
||||
[packages]
|
||||
""".strip())
|
||||
|
||||
c = p.pipenv('sync')
|
||||
assert c.return_code != 0
|
||||
assert 'Pipfile.lock is missing!' in c.err
|
||||
|
||||
|
||||
@pytest.mark.sync
|
||||
@pytest.mark.lock
|
||||
def test_sync_should_not_lock(PipenvInstance, pypi):
|
||||
"""Sync should not touch the lock file, even if Pipfile is changed.
|
||||
"""
|
||||
with PipenvInstance(pypi=pypi) as p:
|
||||
with open(p.pipfile_path, 'w') as f:
|
||||
f.write("""
|
||||
[packages]
|
||||
""".strip())
|
||||
|
||||
# Perform initial lock.
|
||||
c = p.pipenv('lock')
|
||||
assert c.return_code == 0
|
||||
lockfile_content = p.lockfile
|
||||
assert lockfile_content
|
||||
|
||||
# Make sure sync does not trigger lockfile update.
|
||||
with open(p.pipfile_path, 'w') as f:
|
||||
f.write("""
|
||||
[packages]
|
||||
six = "*"
|
||||
""".strip())
|
||||
c = p.pipenv('sync')
|
||||
assert c.return_code == 0
|
||||
assert lockfile_content == p.lockfile
|
||||
+15
-15
@@ -44,7 +44,21 @@ DEP_PIP_PAIRS = [
|
||||
}},
|
||||
'-e svn+svn://svn.myproject.org/svn/MyProject#egg=MyProject',
|
||||
),
|
||||
|
||||
(
|
||||
# Extras in url
|
||||
{'discord.py': {
|
||||
'file': 'https://github.com/Rapptz/discord.py/archive/rewrite.zip',
|
||||
'extras': ['voice']
|
||||
}},
|
||||
'https://github.com/Rapptz/discord.py/archive/rewrite.zip#egg=discord.py[voice]',
|
||||
),
|
||||
(
|
||||
{'requests': {
|
||||
'git': 'https://github.com/requests/requests.git',
|
||||
'ref': 'master', 'extras': ['security'],
|
||||
}},
|
||||
'git+https://github.com/requests/requests.git@master#egg=requests[security]',
|
||||
),
|
||||
]
|
||||
|
||||
|
||||
@@ -97,20 +111,6 @@ def test_convert_from_pip(expected, requirement):
|
||||
assert pipenv.utils.convert_deps_from_pip(requirement) == expected
|
||||
|
||||
|
||||
@pytest.mark.utils
|
||||
@pytest.mark.parametrize('expected, requirement', [
|
||||
( # XXX: This should work the other way around as well, but does not atm.
|
||||
{'requests': {
|
||||
'git': 'https://github.com/requests/requests.git',
|
||||
'ref': 'master', 'extras': ['security'],
|
||||
}},
|
||||
'git+https://github.com/requests/requests.git@master#egg=requests[security]',
|
||||
),
|
||||
])
|
||||
def test_convert_from_pip_vcs_with_extra(expected, requirement):
|
||||
assert pipenv.utils.convert_deps_from_pip(requirement) == expected
|
||||
|
||||
|
||||
@pytest.mark.utils
|
||||
def test_convert_from_pip_fail_if_no_egg():
|
||||
"""Parsing should fail without `#egg=`.
|
||||
|
||||
Reference in New Issue
Block a user