mirror of
https://github.com/kennethreitz/pipenv.git
synced 2026-06-05 22:50:18 +00:00
Merge branch 'master' of https://github.com/kennethreitz/pipenv
This commit is contained in:
+11
-11
@@ -1,24 +1,24 @@
|
||||
FROM python:3.6.2
|
||||
FROM python:3.6.3
|
||||
|
||||
# -- Install Pipenv:
|
||||
RUN pip install pipenv --upgrade
|
||||
RUN set -ex && pip install pipenv --upgrade
|
||||
|
||||
# -- Install Application into container:
|
||||
RUN mkdir /app
|
||||
RUN set -ex && mkdir /app
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
# -- Adding Pipfiles
|
||||
ONBUILD COPY Pipfile Pipfile
|
||||
ONBUILD COPY Pipfile.lock Pipfile.lock
|
||||
|
||||
# -- Install dependencies:
|
||||
ONBUILD RUN set -ex && pipenv install --deploy --system
|
||||
|
||||
# --------------------
|
||||
# - Using This File: -
|
||||
# --------------------
|
||||
|
||||
# FROM kennethreitz/pipenv
|
||||
|
||||
# COPY Pipfile Pipfile
|
||||
# COPY Pipfile.lock Pipfile.lock
|
||||
# COPY . /app
|
||||
|
||||
# -- Install dependencies:
|
||||
# RUN pipenv install --deploy --system
|
||||
|
||||
ENTRYPOINT []
|
||||
CMD [ "/bin/bash" ]
|
||||
@@ -1,4 +1,5 @@
|
||||
include README.rst LICENSE NOTICES HISTORY.txt pipenv/patched/safety.zip
|
||||
include pipenv/patched/pip/_vendor/requests/cacert.pem
|
||||
include pipenv/vendor/pipreqs/stdlib
|
||||
include pipenv/vendor/pipreqs/mapping
|
||||
include pipenv/pipenv.1
|
||||
|
||||
@@ -220,6 +220,16 @@ To upgrade pipenv at any time::
|
||||
|
||||
This will install both ``pipenv`` and ``pew`` (one of our dependencies) in an isolated virtualenv, so it doesn't interfere with the rest of your Python installation!
|
||||
|
||||
.. _more_proper_installation:
|
||||
|
||||
☤ Referentially Transparent Installation of Pipenv
|
||||
==================================================
|
||||
|
||||
Nix provides atomic upgrades and rollbacks, it's reliable and reproducible thanks to keeping all dependencies isolated all the way down to libc.
|
||||
|
||||
`Once installed <https://nixos.org/nix/>`_ simply run::
|
||||
|
||||
$ nix-env --install --attr pipenv
|
||||
|
||||
.. _pragmatic_installation:
|
||||
|
||||
|
||||
+32
-16
@@ -25,19 +25,17 @@ import pipdeptree
|
||||
import requirements
|
||||
import semver
|
||||
import flake8.main.cli
|
||||
|
||||
from pipreqs import pipreqs
|
||||
from blindspin import spinner
|
||||
from urllib3.exceptions import InsecureRequestWarning
|
||||
from pip.req.req_file import parse_requirements
|
||||
from click_didyoumean import DYMCommandCollection
|
||||
|
||||
from .project import Project
|
||||
from .utils import (
|
||||
convert_deps_from_pip, convert_deps_to_pip, is_required_version,
|
||||
proper_case, pep423_name, split_vcs, resolve_deps, shellquote, is_vcs,
|
||||
python_version, suggest_package, find_windows_executable, is_file,
|
||||
prepare_pip_source_args, is_valid_url, download_file
|
||||
prepare_pip_source_args, temp_environ, is_valid_url, download_file
|
||||
)
|
||||
from .__version__ import __version__
|
||||
from . import pep508checker, progress
|
||||
@@ -565,11 +563,15 @@ def ensure_virtualenv(three=None, python=None, site_packages=False):
|
||||
|
||||
# If --three, --two, or --python were passed...
|
||||
elif (python) or (three is not None) or (site_packages is not False):
|
||||
click.echo(crayons.red('Virtualenv already exists!'), err=True)
|
||||
click.echo(crayons.normal(u'Removing existing virtualenv…', bold=True), err=True)
|
||||
|
||||
USING_DEFAULT_PYTHON = False
|
||||
|
||||
# Ensure python is installed before deleting existing virtual env
|
||||
ensure_python(three=three, python=python)
|
||||
|
||||
click.echo(crayons.red('Virtualenv already exists!'), err=True)
|
||||
click.echo(crayons.normal(u'Removing existing virtualenv…', bold=True), err=True)
|
||||
|
||||
# Remove the virtualenv.
|
||||
cleanup_virtualenv(bare=True)
|
||||
|
||||
@@ -2030,29 +2032,43 @@ def do_shell(three=None, python=False, fancy=False, shell_args=None):
|
||||
|
||||
# Standard (properly configured shell) mode:
|
||||
else:
|
||||
if PIPENV_VENV_IN_PROJECT:
|
||||
# use .venv as the target virtualenv name
|
||||
workon_name = '.venv'
|
||||
else:
|
||||
workon_name = project.virtualenv_name
|
||||
|
||||
cmd = 'pew'
|
||||
args = ["workon", project.virtualenv_name]
|
||||
args = ["workon", workon_name]
|
||||
|
||||
# Grab current terminal dimensions to replace the hardcoded default
|
||||
# dimensions of pexpect
|
||||
terminal_dimensions = get_terminal_size()
|
||||
|
||||
try:
|
||||
c = pexpect.spawn(
|
||||
cmd,
|
||||
args,
|
||||
dimensions=(
|
||||
terminal_dimensions.lines,
|
||||
terminal_dimensions.columns
|
||||
with temp_environ():
|
||||
if PIPENV_VENV_IN_PROJECT:
|
||||
os.environ['WORKON_HOME'] = project.project_directory
|
||||
|
||||
c = pexpect.spawn(
|
||||
cmd,
|
||||
args,
|
||||
dimensions=(
|
||||
terminal_dimensions.lines,
|
||||
terminal_dimensions.columns
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
# Windows!
|
||||
except AttributeError:
|
||||
import subprocess
|
||||
p = subprocess.Popen([cmd] + list(args), shell=True, universal_newlines=True)
|
||||
p.communicate()
|
||||
sys.exit(p.returncode)
|
||||
# Tell pew to use the project directory as its workon_home
|
||||
with temp_environ():
|
||||
if PIPENV_VENV_IN_PROJECT:
|
||||
os.environ['WORKON_HOME'] = project.project_directory
|
||||
p = subprocess.Popen([cmd] + list(args), shell=True, universal_newlines=True)
|
||||
p.communicate()
|
||||
sys.exit(p.returncode)
|
||||
|
||||
# Activate the virtualenv if in compatibility mode.
|
||||
if compat:
|
||||
|
||||
+19
-4
@@ -23,6 +23,7 @@ try:
|
||||
except ImportError:
|
||||
from urlparse import urlparse
|
||||
|
||||
from contextlib import contextmanager
|
||||
from piptools.resolver import Resolver
|
||||
from piptools.repositories.pypi import PyPIRepository
|
||||
from piptools.scripts.compile import get_pip_command
|
||||
@@ -341,6 +342,9 @@ def shellquote(s):
|
||||
"""Prepares a string for the shell (on Windows too!)"""
|
||||
if s is None:
|
||||
return None
|
||||
# Additional escaping for windows paths
|
||||
if os.name == 'nt':
|
||||
s = "{}".format(s.replace("\\", "\\\\"))
|
||||
|
||||
return '"' + s.replace("'", "'\\''") + '"'
|
||||
|
||||
@@ -530,8 +534,8 @@ def convert_deps_from_pip(dep):
|
||||
extras = {'extras': req.extras}
|
||||
|
||||
# File installs.
|
||||
if (req.uri or (os.path.exists(req.path) if req.path else False) or
|
||||
os.path.exists(req.name)) and not req.vcs:
|
||||
if (req.uri or (os.path.isfile(req.path) if req.path else False) or
|
||||
os.path.isfile(req.name)) and not req.vcs:
|
||||
# Assign a package name to the file, last 7 of it's sha256 hex digest.
|
||||
if not req.uri and not req.path:
|
||||
req.path = os.path.abspath(req.name)
|
||||
@@ -850,8 +854,7 @@ def get_windows_path(*args):
|
||||
"""Sanitize a path for windows environments
|
||||
|
||||
Accepts an arbitrary list of arguments and makes a clean windows path"""
|
||||
clean_path = os.path.join(*args)
|
||||
return os.path.normpath(clean_path)
|
||||
return os.path.normpath(os.path.join(*args))
|
||||
|
||||
|
||||
def find_windows_executable(bin_path, exe_name):
|
||||
@@ -915,6 +918,18 @@ def find_requirements(max_depth=3):
|
||||
raise RuntimeError('No requirements.txt found!')
|
||||
|
||||
|
||||
# Borrowed from pew to avoid importing pew which imports psutil
|
||||
# See https://github.com/berdario/pew/blob/master/pew/_utils.py#L82
|
||||
@contextmanager
|
||||
def temp_environ():
|
||||
"""Allow the ability to set os.environ temporarily"""
|
||||
environ = dict(os.environ)
|
||||
try:
|
||||
yield
|
||||
finally:
|
||||
os.environ.clear()
|
||||
os.environ.update(environ)
|
||||
|
||||
def is_valid_url(url):
|
||||
"""Checks if a given string is an url"""
|
||||
pieces = urlparse(url)
|
||||
|
||||
+89
-25
@@ -6,6 +6,7 @@ import json
|
||||
import pytest
|
||||
|
||||
from pipenv.cli import activate_virtualenv
|
||||
from pipenv.utils import temp_environ, get_windows_path
|
||||
from pipenv.vendor import toml
|
||||
from pipenv.vendor import delegator
|
||||
from pipenv.project import Project
|
||||
@@ -227,6 +228,24 @@ class TestPipenv:
|
||||
c = p.pipenv('run python -m requests.help')
|
||||
assert c.return_code > 0
|
||||
|
||||
@pytest.mark.files
|
||||
@pytest.mark.run
|
||||
@pytest.mark.uninstall
|
||||
def test_uninstall_all_local_files(self):
|
||||
file_name = 'tablib-0.12.1.tar.gz'
|
||||
# Not sure where travis/appveyor run tests from
|
||||
test_dir = os.path.dirname(os.path.abspath(__file__))
|
||||
source_path = os.path.abspath(os.path.join(test_dir, 'test_artifacts', file_name))
|
||||
|
||||
with PipenvInstance() as p:
|
||||
shutil.copy(source_path, os.path.join(p.path, file_name))
|
||||
os.mkdir(os.path.join(p.path, "tablib"))
|
||||
c = p.pipenv('install {}'.format(file_name))
|
||||
c = p.pipenv('uninstall --all --verbose')
|
||||
assert c.return_code == 0
|
||||
assert 'tablib' in c.out
|
||||
assert 'tablib' not in p.pipfile['packages']
|
||||
|
||||
@pytest.mark.extras
|
||||
@pytest.mark.install
|
||||
def test_extras_install(self):
|
||||
@@ -271,33 +290,32 @@ class TestPipenv:
|
||||
@pytest.mark.run
|
||||
@pytest.mark.install
|
||||
def test_multiprocess_bug_and_install(self):
|
||||
os.environ['PIPENV_MAX_SUBPROCESS'] = '2'
|
||||
with temp_environ():
|
||||
os.environ['PIPENV_MAX_SUBPROCESS'] = '2'
|
||||
|
||||
with PipenvInstance() as p:
|
||||
with open(p.pipfile_path, 'w') as f:
|
||||
contents = """
|
||||
with PipenvInstance() as p:
|
||||
with open(p.pipfile_path, 'w') as f:
|
||||
contents = """
|
||||
[packages]
|
||||
requests = "*"
|
||||
records = "*"
|
||||
tpfd = "*"
|
||||
""".strip()
|
||||
f.write(contents)
|
||||
""".strip()
|
||||
f.write(contents)
|
||||
|
||||
c = p.pipenv('install')
|
||||
assert c.return_code == 0
|
||||
c = p.pipenv('install')
|
||||
assert c.return_code == 0
|
||||
|
||||
assert 'requests' in p.lockfile['default']
|
||||
assert 'idna' in p.lockfile['default']
|
||||
assert 'urllib3' in p.lockfile['default']
|
||||
assert 'certifi' in p.lockfile['default']
|
||||
assert 'records' in p.lockfile['default']
|
||||
assert 'tpfd' in p.lockfile['default']
|
||||
assert 'parse' in p.lockfile['default']
|
||||
assert 'requests' in p.lockfile['default']
|
||||
assert 'idna' in p.lockfile['default']
|
||||
assert 'urllib3' in p.lockfile['default']
|
||||
assert 'certifi' in p.lockfile['default']
|
||||
assert 'records' in p.lockfile['default']
|
||||
assert 'tpfd' in p.lockfile['default']
|
||||
assert 'parse' in p.lockfile['default']
|
||||
|
||||
c = p.pipenv('run python -c "import requests; import idna; import certifi; import records; import tpfd; import parse;"')
|
||||
assert c.return_code == 0
|
||||
|
||||
del os.environ['PIPENV_MAX_SUBPROCESS']
|
||||
c = p.pipenv('run python -c "import requests; import idna; import certifi; import records; import tpfd; import parse;"')
|
||||
assert c.return_code == 0
|
||||
|
||||
@pytest.mark.sequential
|
||||
@pytest.mark.install
|
||||
@@ -445,14 +463,60 @@ requests = {version = "*"}
|
||||
@pytest.mark.dotvenv
|
||||
def test_venv_in_project(self):
|
||||
|
||||
os.environ['PIPENV_VENV_IN_PROJECT'] = '1'
|
||||
with PipenvInstance() as p:
|
||||
c = p.pipenv('install requests')
|
||||
assert c.return_code == 0
|
||||
with temp_environ():
|
||||
os.environ['PIPENV_VENV_IN_PROJECT'] = '1'
|
||||
with PipenvInstance() as p:
|
||||
c = p.pipenv('install requests')
|
||||
assert c.return_code == 0
|
||||
|
||||
assert p.path in p.pipenv('--venv').out
|
||||
assert p.path in p.pipenv('--venv').out
|
||||
|
||||
@pytest.mark.dotvenv
|
||||
@pytest.mark.install
|
||||
@pytest.mark.complex
|
||||
@pytest.mark.shell
|
||||
@pytest.mark.windows
|
||||
@pytest.mark.pew
|
||||
def test_shell_nested_venv_in_project(self):
|
||||
import subprocess
|
||||
with temp_environ():
|
||||
os.environ['PIPENV_VENV_IN_PROJECT'] = '1'
|
||||
os.environ['PIPENV_IGNORE_VIRTUALENVS'] = '1'
|
||||
os.environ['PIPENV_SHELL_COMPAT'] = '1'
|
||||
with PipenvInstance(chdir=True) as p:
|
||||
# Signal to pew to look in the project directory for the environment
|
||||
os.environ['WORKON_HOME'] = p.path
|
||||
project = Project()
|
||||
c = p.pipenv('install requests')
|
||||
assert c.return_code == 0
|
||||
assert 'requests' in p.pipfile['packages']
|
||||
assert 'requests' in p.lockfile['default']
|
||||
# Check that .venv now shows in pew's managed list
|
||||
pew_list = delegator.run('pew ls')
|
||||
assert '.venv' in pew_list.out
|
||||
# Check for the venv directory
|
||||
c = delegator.run('pew dir .venv')
|
||||
# Compare pew's virtualenv path to what we expect
|
||||
venv_path = get_windows_path(project.project_directory, '.venv')
|
||||
# os.path.normpath will normalize slashes
|
||||
assert venv_path == os.path.normpath(c.out.strip())
|
||||
# Have pew run 'pip freeze' in the virtualenv
|
||||
# This is functionally the same as spawning a subshell
|
||||
# If we can do this we can theoretically amke a subshell
|
||||
# This test doesn't work on *nix
|
||||
if os.name == 'nt':
|
||||
args = ['pew', 'in', '.venv', 'pip', 'freeze']
|
||||
process = subprocess.Popen(
|
||||
args,
|
||||
shell=True,
|
||||
universal_newlines=True,
|
||||
stdin=subprocess.PIPE,
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=subprocess.PIPE
|
||||
)
|
||||
out, _ = process.communicate()
|
||||
assert any(req.startswith('requests') for req in out.splitlines()) is True
|
||||
|
||||
del os.environ['PIPENV_VENV_IN_PROJECT']
|
||||
|
||||
@pytest.mark.run
|
||||
@pytest.mark.dotenv
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
import os
|
||||
import pytest
|
||||
from mock import patch, Mock
|
||||
|
||||
@@ -165,3 +166,10 @@ class TestUtils:
|
||||
run_ret.out = version_output
|
||||
mocked_delegator.return_value = run_ret
|
||||
assert pipenv.utils.python_version('some/path') == version
|
||||
|
||||
@pytest.mark.windows
|
||||
@pytest.mark.skipif(os.name != 'nt', reason='Windows test only')
|
||||
def test_windows_shellquote(self):
|
||||
test_path = 'C:\Program Files\Python36\python.exe'
|
||||
expected_path = '"C:\\\\Program Files\\\\Python36\\\\python.exe"'
|
||||
assert pipenv.utils.shellquote(test_path) == expected_path
|
||||
|
||||
Reference in New Issue
Block a user