Split apart core.py (#5616)

* Split apart core using pycharm refactor move methods.
This commit is contained in:
Matt Davis
2023-02-24 18:25:00 -05:00
committed by GitHub
parent 34b5768128
commit 52f180eb91
25 changed files with 3256 additions and 3284 deletions
+39 -20
View File
@@ -25,6 +25,7 @@ from pipenv.cli.options import (
from pipenv.utils.dependencies import get_lockfile_section_using_pipfile_category
from pipenv.utils.environment import load_dot_env
from pipenv.utils.processes import subprocess_run
from pipenv.vendor import click
from pipenv.vendor.click import (
Choice,
argument,
@@ -85,15 +86,10 @@ def cli(
load_dot_env(state.project, quiet=state.quiet)
from ..core import (
cleanup_virtualenv,
do_clear,
do_py,
do_where,
ensure_project,
format_help,
warn_in_virtualenv,
)
from pipenv.routines.clear import do_clear
from pipenv.utils.display import format_help
from pipenv.utils.project import ensure_project
from pipenv.utils.virtualenv import cleanup_virtualenv, do_where, warn_in_virtualenv
if "PIPENV_COLORBLIND" in os.environ:
echo(
@@ -233,7 +229,7 @@ def cli(
@pass_state
def install(state, **kwargs):
"""Installs provided packages and adds them to Pipfile, or (if no packages are given), installs all packages from Pipfile."""
from ..core import do_install
from pipenv.routines.install import do_install
do_install(
state.project,
@@ -278,7 +274,7 @@ def install(state, **kwargs):
@pass_context
def uninstall(ctx, state, all_dev=False, all=False, **kwargs):
"""Uninstalls a provided package and removes it from Pipfile."""
from ..core import do_uninstall
from pipenv.routines.uninstall import do_uninstall
retcode = do_uninstall(
state.project,
@@ -320,7 +316,8 @@ LOCK_DEV_NOTE = """\
@pass_context
def lock(ctx, state, **kwargs):
"""Generates Pipfile.lock."""
from ..core import do_lock, ensure_project
from pipenv.routines.lock import do_lock
from pipenv.utils.project import ensure_project
# Ensure that virtualenv is available.
# Note that we don't pass clear on to ensure_project as it is also
@@ -373,7 +370,7 @@ def shell(
anyway=False,
):
"""Spawns a shell within the virtualenv."""
from ..core import do_shell
from pipenv.routines.shell import do_shell
# Prevent user from activating nested environments.
if "PIPENV_ACTIVE" in os.environ:
@@ -413,7 +410,7 @@ def shell(
@pass_state
def run(state, command, args):
"""Spawns a command installed into the virtualenv."""
from ..core import do_run
from pipenv.routines.shell import do_run
do_run(
state.project,
@@ -510,7 +507,7 @@ def check(
**kwargs,
):
"""Checks for PyUp Safety security vulnerabilities and against PEP 508 markers provided in Pipfile."""
from ..core import do_check
from pipenv.routines.check import do_check
do_check(
state.project,
@@ -541,7 +538,10 @@ def check(
@pass_context
def update(ctx, state, bare=False, dry_run=None, outdated=False, **kwargs):
"""Runs lock, then sync."""
from ..core import do_lock, do_outdated, do_sync, ensure_project
from pipenv.routines.install import do_sync
from pipenv.routines.lock import do_lock
from pipenv.routines.outdated import do_outdated
from pipenv.utils.project import ensure_project
ensure_project(
state.project,
@@ -618,7 +618,7 @@ def update(ctx, state, bare=False, dry_run=None, outdated=False, **kwargs):
@pass_state
def graph(state, bare=False, json=False, json_tree=False, reverse=False):
"""Displays currently-installed dependency graph information."""
from ..core import do_graph
from pipenv.routines.graph import do_graph
do_graph(state.project, bare=bare, json=json, json_tree=json_tree, reverse=reverse)
@@ -639,7 +639,8 @@ def run_open(state, module, *args, **kwargs):
EDITOR=atom pipenv open requests
"""
from ..core import ensure_project, inline_activate_virtual_environment
from pipenv.utils.project import ensure_project
from pipenv.utils.virtualenv import inline_activate_virtual_environment
# Ensure that virtualenv is available.
ensure_project(
@@ -679,7 +680,7 @@ def run_open(state, module, *args, **kwargs):
@pass_context
def sync(ctx, state, bare=False, user=False, unused=False, **kwargs):
"""Installs all packages specified in Pipfile.lock."""
from ..core import do_sync
from pipenv.routines.install import do_sync
retcode = do_sync(
state.project,
@@ -710,7 +711,7 @@ def sync(ctx, state, bare=False, user=False, unused=False, **kwargs):
@pass_state
def clean(state, dry_run=False, bare=False, user=False):
"""Uninstalls all packages not specified in Pipfile.lock."""
from ..core import do_clean
from pipenv.routines.clean import do_clean
do_clean(
state.project,
@@ -822,3 +823,21 @@ def requirements(
if __name__ == "__main__":
cli()
def do_py(project, ctx=None, system=False):
if not project.virtualenv_exists:
click.echo(
"{}({}){}".format(
click.style("No virtualenv has been created for this project ", fg="red"),
click.style(project.project_directory, fg="yellow", bold=True),
click.style(" yet!", fg="red"),
),
err=True,
)
ctx.abort()
try:
click.echo(project._which("python", allow_global=system))
except AttributeError:
click.echo(click.style("No project found!", fg="red"))
+1 -1
View File
@@ -24,7 +24,7 @@ class PipenvGroup(DYMMixin, Group):
"""Custom Group class provides formatted main help"""
def get_help_option(self, ctx):
from ..core import format_help
from pipenv.utils.display import format_help
"""Override for showing formatted main help via --help and -h options"""
help_options = self.get_help_option_names(ctx)
-3259
View File
File diff suppressed because it is too large Load Diff
View File
+249
View File
@@ -0,0 +1,249 @@
import io
import json as simplejson
import os
import sys
import tempfile
from pathlib import Path
from pipenv import exceptions, pep508checker
from pipenv.utils.processes import run_command
from pipenv.utils.project import ensure_project
from pipenv.utils.shell import cmd_list_to_shell, project_python
from pipenv.vendor import click, plette
def do_check(
project,
python=False,
system=False,
db=None,
ignore=None,
output="screen",
key=None,
quiet=False,
exit_code=True,
policy_file="",
save_json="",
audit_and_monitor=True,
safety_project=None,
pypi_mirror=None,
use_installed=False,
categories="",
):
import json
if not system:
# Ensure that virtualenv is available.
ensure_project(
project,
python=python,
validate=False,
warn=False,
pypi_mirror=pypi_mirror,
)
if not quiet and not project.s.is_quiet():
click.secho("Checking PEP 508 requirements...", bold=True)
pep508checker_path = pep508checker.__file__.rstrip("cdo")
safety_path = os.path.join(
os.path.dirname(os.path.abspath(__file__)), "patched", "safety"
)
_cmd = [project_python(project, system=system)]
# Run the PEP 508 checker in the virtualenv.
cmd = _cmd + [Path(pep508checker_path).as_posix()]
c = run_command(cmd, is_verbose=project.s.is_verbose())
results = []
if c.returncode is not None:
try:
results = simplejson.loads(c.stdout.strip())
except json.JSONDecodeError:
click.echo(
"{}\n{}\n{}".format(
click.style(
"Failed parsing pep508 results: ",
fg="white",
bold=True,
),
c.stdout.strip(),
c.stderr.strip(),
)
)
sys.exit(1)
# Load the pipfile.
p = plette.Pipfile.load(open(project.pipfile_location))
p = plette.Lockfile.with_meta_from(p)
failed = False
# Assert each specified requirement.
for marker, specifier in p._data["_meta"]["requires"].items():
if marker in results:
try:
assert results[marker] == specifier
except AssertionError:
failed = True
click.echo(
"Specifier {} does not match {} ({})."
"".format(
click.style(marker, fg="green"),
click.style(specifier, fg="cyan"),
click.style(results[marker], fg="yellow"),
),
err=True,
)
if failed:
click.secho("Failed!", fg="red", err=True)
sys.exit(1)
else:
if not quiet and not project.s.is_quiet():
click.secho("Passed!", fg="green")
if not quiet and not project.s.is_quiet():
click.secho(
"Checking installed packages for vulnerabilities...",
bold=True,
)
if ignore:
if not isinstance(ignore, (tuple, list)):
ignore = [ignore]
ignored = [["--ignore", cve] for cve in ignore]
if not quiet and not project.s.is_quiet():
click.echo(
"Notice: Ignoring Vulnerabilit{} {}".format(
"ies" if len(ignored) > 1 else "y",
click.style(", ".join(ignore), fg="yellow"),
),
err=True,
)
else:
ignored = []
options = [
"--audit-and-monitor" if audit_and_monitor else "--disable-audit-and-monitor",
"--exit-code" if exit_code else "--continue-on-error",
]
if output == "full-report":
options.append("--full-report")
elif output == "minimal":
options.append("--json")
elif output not in ["screen", "default"]:
options.append(f"--output={output}")
if save_json:
options.append(f"--save-json={save_json}")
if policy_file:
options.append(f"--policy-file={policy_file}")
if safety_project:
options.append(f"--project={safety_project}")
if use_installed:
target_venv_packages = run_command(
_cmd + ["-m", "pip", "list", "--format=freeze"],
is_verbose=project.s.is_verbose(),
)
elif categories:
target_venv_packages = run_command(
["pipenv", "requirements", "--categories", categories],
is_verbose=project.s.is_verbose(),
)
else:
target_venv_packages = run_command(
["pipenv", "requirements"], is_verbose=project.s.is_verbose()
)
temp_requirements = tempfile.NamedTemporaryFile(
mode="w+",
prefix=f"{project.virtualenv_name}",
suffix="_requirements.txt",
delete=False,
)
temp_requirements.write(target_venv_packages.stdout.strip())
temp_requirements.close()
options.extend(["--file", temp_requirements.name])
cmd = _cmd + [safety_path, "check"] + options
if db:
if not quiet and not project.s.is_quiet():
click.echo(f"Using {db} database")
cmd.append(f"--db={db}")
elif key or project.s.PIPENV_PYUP_API_KEY:
cmd = cmd + [f"--key={key or project.s.PIPENV_PYUP_API_KEY}"]
else:
PIPENV_SAFETY_DB = (
"https://d2qjmgddvqvu75.cloudfront.net/aws/safety/pipenv/1.0.0/"
)
os.environ["SAFETY_ANNOUNCEMENTS_URL"] = f"{PIPENV_SAFETY_DB}announcements.json"
cmd.append(f"--db={PIPENV_SAFETY_DB}")
if ignored:
for cve in ignored:
cmd += cve
os.environ["SAFETY_CUSTOM_INTEGRATION"] = "True"
os.environ["SAFETY_SOURCE"] = "pipenv"
os.environ["SAFETY_PURE_YAML"] = "True"
from pipenv.patched.safety.cli import cli
sys.argv = cmd[1:]
if output == "minimal":
from contextlib import redirect_stderr, redirect_stdout
code = 0
with redirect_stdout(io.StringIO()) as out, redirect_stderr(io.StringIO()) as err:
try:
cli(prog_name="pipenv")
except SystemExit as exit_signal:
code = exit_signal.code
report = out.getvalue()
error = err.getvalue()
try:
json_report = simplejson.loads(report)
except Exception:
raise exceptions.PipenvCmdError(
cmd_list_to_shell(cmd), report, error, exit_code=code
)
meta = json_report.get("report_meta")
vulnerabilities_found = meta.get("vulnerabilities_found")
fg = "green"
message = "All good!"
db_type = "commercial" if meta.get("api_key", False) else "free"
if vulnerabilities_found >= 0:
fg = "red"
message = (
f"Scan was complete using Safetys {db_type} vulnerability database."
)
click.echo()
click.secho(f"{vulnerabilities_found} vulnerabilities found.", fg=fg)
click.echo()
vulnerabilities = json_report.get("vulnerabilities", [])
for vuln in vulnerabilities:
click.echo(
"{}: {} {} open to vulnerability {} ({}). More info: {}".format(
click.style(vuln["vulnerability_id"], bold=True, fg="red"),
click.style(vuln["package_name"], fg="green"),
click.style(vuln["analyzed_version"], fg="yellow", bold=True),
click.style(vuln["vulnerability_id"], bold=True),
click.style(vuln["vulnerable_spec"], fg="yellow", bold=False),
click.style(vuln["more_info_url"], bold=True),
)
)
click.echo(f"{vuln['advisory']}")
click.echo()
click.secho(message, fg="white", bold=True)
sys.exit(code)
cli(prog_name="pipenv")
temp_requirements.remove()
+85
View File
@@ -0,0 +1,85 @@
import sys
from pipenv.patched.pip._internal.build_env import get_runnable_pip
from pipenv.routines.lock import do_lock
from pipenv.utils.processes import run_command
from pipenv.utils.project import ensure_project
from pipenv.utils.requirements import BAD_PACKAGES
from pipenv.utils.shell import project_python
from pipenv.vendor import click
def do_clean(
project,
python=None,
dry_run=False,
bare=False,
pypi_mirror=None,
system=False,
):
# Ensure that virtualenv is available.
from pipenv.patched.pip._vendor.packaging.utils import canonicalize_name
ensure_project(project, python=python, validate=False, pypi_mirror=pypi_mirror)
ensure_lockfile(project, pypi_mirror=pypi_mirror)
# Make sure that the virtualenv's site packages are configured correctly
# otherwise we may end up removing from the global site packages directory
installed_package_names = project.installed_package_names.copy()
# Remove known "bad packages" from the list.
for bad_package in BAD_PACKAGES:
if canonicalize_name(bad_package) in installed_package_names:
if project.s.is_verbose():
click.echo(f"Ignoring {bad_package}.", err=True)
installed_package_names.remove(canonicalize_name(bad_package))
# Intelligently detect if --dev should be used or not.
locked_packages = {
canonicalize_name(pkg) for pkg in project.lockfile_package_names["combined"]
}
for used_package in locked_packages:
if used_package in installed_package_names:
installed_package_names.remove(used_package)
failure = False
for apparent_bad_package in installed_package_names:
if dry_run and not bare:
click.echo(apparent_bad_package)
else:
if not bare:
click.secho(
f"Uninstalling {apparent_bad_package}...",
fg="white",
bold=True,
)
# Uninstall the package.
cmd = [
project_python(project, system=system),
get_runnable_pip(),
"uninstall",
apparent_bad_package,
"-y",
]
c = run_command(cmd, is_verbose=project.s.is_verbose())
if c.returncode != 0:
failure = True
sys.exit(int(failure))
def ensure_lockfile(project, keep_outdated=False, pypi_mirror=None):
"""Ensures that the lockfile is up-to-date."""
if not keep_outdated:
keep_outdated = project.settings.get("keep_outdated")
# Write out the lockfile if it doesn't exist, but not if the Pipfile is being ignored
if project.lockfile_exists:
old_hash = project.get_lockfile_hash()
new_hash = project.calculate_pipfile_hash()
if new_hash != old_hash:
click.secho(
"Pipfile.lock ({}) out of date, updating to ({})...".format(
old_hash[-6:], new_hash[-6:]
),
fg="yellow",
bold=True,
err=True,
)
do_lock(project, keep_outdated=keep_outdated, pypi_mirror=pypi_mirror)
else:
do_lock(project, keep_outdated=keep_outdated, pypi_mirror=pypi_mirror)
+27
View File
@@ -0,0 +1,27 @@
import shutil
from pipenv import environments
from pipenv.vendor import click, vistir
def do_clear(project):
from pipenv.patched.pip._internal import locations
click.secho("Clearing caches...", bold=True)
try:
shutil.rmtree(
project.s.PIPENV_CACHE_DIR, onerror=vistir.path.handle_remove_readonly
)
# Other processes may be writing into this directory simultaneously.
shutil.rmtree(
locations.USER_CACHE_DIR,
ignore_errors=environments.PIPENV_IS_CI,
onerror=vistir.path.handle_remove_readonly,
)
except OSError as e:
# Ignore FileNotFoundError. This is needed for Python 2.7.
import errno
if e.errno == errno.ENOENT:
pass
raise
+149
View File
@@ -0,0 +1,149 @@
import json as simplejson
import os
import sys
from pathlib import Path
from pipenv import exceptions
from pipenv.utils.processes import run_command
from pipenv.utils.requirements import BAD_PACKAGES
from pipenv.vendor import click
def do_graph(project, bare=False, json=False, json_tree=False, reverse=False):
import json as jsonlib
from pipenv.vendor import pipdeptree
pipdeptree_path = os.path.dirname(pipdeptree.__file__.rstrip("cdo"))
try:
python_path = project._which("python")
except AttributeError:
click.echo(
"{}: {}".format(
click.style("Warning", fg="red", bold=True),
"Unable to display currently-installed dependency graph information here. "
"Please run within a Pipenv project.",
),
err=True,
)
sys.exit(1)
except RuntimeError:
pass
else:
if not os.name == "nt": # bugfix #4388
python_path = Path(python_path).as_posix()
pipdeptree_path = Path(pipdeptree_path).as_posix()
if reverse and json:
click.echo(
"{}: {}".format(
click.style("Warning", fg="red", bold=True),
"Using both --reverse and --json together is not supported. "
"Please select one of the two options.",
),
err=True,
)
sys.exit(1)
if reverse and json_tree:
click.echo(
"{}: {}".format(
click.style("Warning", fg="red", bold=True),
"Using both --reverse and --json-tree together is not supported. "
"Please select one of the two options.",
),
err=True,
)
sys.exit(1)
if json and json_tree:
click.echo(
"{}: {}".format(
click.style("Warning", fg="red", bold=True),
"Using both --json and --json-tree together is not supported. "
"Please select one of the two options.",
),
err=True,
)
sys.exit(1)
flag = ""
if json:
flag = "--json"
if json_tree:
flag = "--json-tree"
if reverse:
flag = "--reverse"
if not project.virtualenv_exists:
click.echo(
"{}: No virtualenv has been created for this project yet! Consider "
"running {} first to automatically generate one for you or see "
"{} for further instructions.".format(
click.style("Warning", fg="red", bold=True),
click.style("`pipenv install`", fg="green"),
click.style("`pipenv install --help`", fg="green"),
),
err=True,
)
sys.exit(1)
cmd_args = [python_path, pipdeptree_path, "-l"]
if flag:
cmd_args.append(flag)
c = run_command(cmd_args, is_verbose=project.s.is_verbose())
# Run dep-tree.
if not bare:
if json:
data = []
try:
parsed = simplejson.loads(c.stdout.strip())
except jsonlib.JSONDecodeError:
raise exceptions.JSONParseError(c.stdout, c.stderr)
else:
for d in parsed:
if d["package"]["key"] not in BAD_PACKAGES:
data.append(d)
click.echo(simplejson.dumps(data, indent=4))
sys.exit(0)
elif json_tree:
def traverse(obj):
if isinstance(obj, list):
return [
traverse(package)
for package in obj
if package["key"] not in BAD_PACKAGES
]
else:
obj["dependencies"] = traverse(obj["dependencies"])
return obj
try:
parsed = simplejson.loads(c.stdout.strip())
except jsonlib.JSONDecodeError:
raise exceptions.JSONParseError(c.stdout, c.stderr)
else:
data = traverse(parsed)
click.echo(simplejson.dumps(data, indent=4))
sys.exit(0)
else:
for line in c.stdout.strip().split("\n"):
# Ignore bad packages as top level.
# TODO: This should probably be a "==" in + line.partition
if line.split("==")[0] in BAD_PACKAGES and not reverse:
continue
# Bold top-level packages.
if not line.startswith(" "):
click.echo(click.style(line, bold=True))
# Echo the rest.
else:
click.echo(click.style(line, bold=False))
else:
click.echo(c.stdout)
if c.returncode != 0:
click.echo(
"{} {}".format(
click.style("ERROR: ", fg="red", bold=True),
click.style(f"{c.stderr}", fg="white"),
),
err=True,
)
# Return its return code.
sys.exit(c.returncode)
+867
View File
@@ -0,0 +1,867 @@
import os
import queue
import sys
import warnings
from collections import defaultdict
from pipenv import environments, exceptions
from pipenv.patched.pip._internal.exceptions import PipError
from pipenv.patched.pip._vendor import rich
from pipenv.routines.lock import do_lock
from pipenv.utils.dependencies import convert_deps_to_pip, is_star
from pipenv.utils.indexes import get_source_list
from pipenv.utils.internet import download_file, is_valid_url
from pipenv.utils.pip import (
format_pip_error,
format_pip_output,
get_trusted_hosts,
pip_install,
pip_install_deps,
)
from pipenv.utils.pipfile import ensure_pipfile
from pipenv.utils.project import ensure_project
from pipenv.utils.requirements import import_requirements
from pipenv.utils.virtualenv import cleanup_virtualenv, do_create_virtualenv
from pipenv.vendor import click, vistir
console = rich.console.Console()
err = rich.console.Console(stderr=True)
def do_install(
project,
packages=False,
editable_packages=False,
index_url=False,
dev=False,
python=False,
pypi_mirror=None,
system=False,
ignore_pipfile=False,
skip_lock=False,
requirementstxt=False,
pre=False,
deploy=False,
keep_outdated=False,
selective_upgrade=False,
site_packages=None,
extra_pip_args=None,
categories=None,
):
requirements_directory = vistir.path.create_tracked_tempdir(
suffix="-requirements", prefix="pipenv-"
)
warnings.filterwarnings("default", category=ResourceWarning)
if selective_upgrade:
keep_outdated = True
packages = packages if packages else []
editable_packages = editable_packages if editable_packages else []
package_args = [p for p in packages if p] + [p for p in editable_packages if p]
skip_requirements = False
# Don't search for requirements.txt files if the user provides one
if requirementstxt or package_args or project.pipfile_exists:
skip_requirements = True
# Ensure that virtualenv is available and pipfile are available
ensure_project(
project,
python=python,
system=system,
warn=True,
deploy=deploy,
skip_requirements=skip_requirements,
pypi_mirror=pypi_mirror,
site_packages=site_packages,
)
# Don't attempt to install develop and default packages if Pipfile is missing
if not project.pipfile_exists and not (package_args or dev):
if not (ignore_pipfile or deploy):
raise exceptions.PipfileNotFound(project.path_to("Pipfile"))
elif ((skip_lock and deploy) or ignore_pipfile) and not project.lockfile_exists:
raise exceptions.LockfileNotFound(project.path_to("Pipfile.lock"))
# Load the --pre settings from the Pipfile.
if not pre:
pre = project.settings.get("allow_prereleases")
if not keep_outdated:
keep_outdated = project.settings.get("keep_outdated")
remote = requirementstxt and is_valid_url(requirementstxt)
if "default" in categories:
raise exceptions.PipenvUsageError(
message="Cannot install to category `default`-- did you mean `packages`?"
)
if "develop" in categories:
raise exceptions.PipenvUsageError(
message="Cannot install to category `develop`-- did you mean `dev-packages`?"
)
# Warn and exit if --system is used without a pipfile.
if (system and package_args) and not project.s.PIPENV_VIRTUALENV:
raise exceptions.SystemUsageError
# Automatically use an activated virtualenv.
if project.s.PIPENV_USE_SYSTEM:
system = True
if system:
project.s.PIPENV_USE_SYSTEM = True
os.environ["PIPENV_USE_SYSTEM"] = "1"
# Check if the file is remote or not
if remote:
click.secho(
"Remote requirements file provided! Downloading...",
bold=True,
err=True,
)
fd = vistir.path.create_tracked_tempfile(
prefix="pipenv-", suffix="-requirement.txt", dir=requirements_directory
)
temp_reqs = fd.name
requirements_url = requirementstxt
# Download requirements file
try:
download_file(requirements_url, temp_reqs, project.s.PIPENV_MAX_RETRIES)
except OSError:
fd.close()
os.unlink(temp_reqs)
click.secho(
f"Unable to find requirements file at {requirements_url}.",
fg="red",
err=True,
)
sys.exit(1)
finally:
fd.close()
# Replace the url with the temporary requirements file
requirementstxt = temp_reqs
remote = True
if requirementstxt:
error, traceback = None, None
click.secho(
"Requirements file provided! Importing into Pipfile...",
bold=True,
err=True,
)
try:
import_requirements(project, r=project.path_to(requirementstxt), dev=dev)
except (UnicodeDecodeError, PipError) as e:
# Don't print the temp file path if remote since it will be deleted.
req_path = requirements_url if remote else project.path_to(requirementstxt)
error = (
"Unexpected syntax in {}. Are you sure this is a "
"requirements.txt style file?".format(req_path)
)
traceback = e
except AssertionError as e:
error = (
"Requirements file doesn't appear to exist. Please ensure the file exists in your "
"project directory or you provided the correct path."
)
traceback = e
finally:
# If requirements file was provided by remote url delete the temporary file
if remote:
fd.close() # Close for windows to allow file cleanup.
os.remove(temp_reqs)
if error and traceback:
click.secho(error, fg="red")
click.secho(str(traceback), fg="yellow", err=True)
sys.exit(1)
# Allow more than one package to be provided.
package_args = [p for p in packages] + [f"-e {pkg}" for pkg in editable_packages]
# Support for --selective-upgrade.
# We should do this part first to make sure that we actually do selectively upgrade
# the items specified
if selective_upgrade:
from pipenv.vendor.requirementslib.models.requirements import Requirement
for i, package in enumerate(package_args[:]):
section = project.packages if not dev else project.dev_packages
package = Requirement.from_line(package)
package__name, package__val = package.pipfile_entry
try:
if not is_star(section[package__name]) and is_star(package__val):
# Support for VCS dependencies.
package_args[i] = convert_deps_to_pip(
{package__name: section[package__name]}, project=project
)[0]
except KeyError:
pass
# Install all dependencies, if none was provided.
# This basically ensures that we have a pipfile and lockfile, then it locks and
# installs from the lockfile
if not packages and not editable_packages:
# Update project settings with pre preference.
if pre:
project.update_settings({"allow_prereleases": pre})
do_init(
project,
dev=dev,
allow_global=system,
ignore_pipfile=ignore_pipfile,
system=system,
skip_lock=skip_lock,
deploy=deploy,
pre=pre,
requirements_dir=requirements_directory,
pypi_mirror=pypi_mirror,
keep_outdated=keep_outdated,
extra_pip_args=extra_pip_args,
categories=categories,
)
# This is for if the user passed in dependencies, then we want to make sure we
else:
from pipenv.vendor.requirementslib.models.requirements import Requirement
# make a tuple of (display_name, entry)
pkg_list = packages + [f"-e {pkg}" for pkg in editable_packages]
if not system and not project.virtualenv_exists:
do_init(
project,
dev=dev,
system=system,
allow_global=system,
keep_outdated=keep_outdated,
requirements_dir=requirements_directory,
deploy=deploy,
pypi_mirror=pypi_mirror,
skip_lock=skip_lock,
extra_pip_args=extra_pip_args,
categories=categories,
)
for pkg_line in pkg_list:
click.secho(
f"Installing {pkg_line}...",
fg="green",
bold=True,
)
# pip install:
with vistir.contextmanagers.temp_environ(), console.status(
"Installing...", spinner=project.s.PIPENV_SPINNER
) as st:
if not system:
os.environ["PIP_USER"] = "0"
if "PYTHONHOME" in os.environ:
del os.environ["PYTHONHOME"]
st.console.print(f"Resolving {pkg_line}...")
try:
pkg_requirement = Requirement.from_line(pkg_line)
except ValueError as e:
err.print("{}: {}".format(click.style("WARNING", fg="red"), e))
err.print(
environments.PIPENV_SPINNER_FAIL_TEXT.format(
"Installation Failed"
)
)
sys.exit(1)
st.console.print("Installing...")
try:
st.update(f"Installing {pkg_requirement.name}...")
if project.s.is_verbose():
st.console.print(
f"Installing package: {pkg_requirement.as_line(include_hashes=False)}"
)
c = pip_install(
project,
pkg_requirement,
ignore_hashes=True,
allow_global=system,
selective_upgrade=selective_upgrade,
no_deps=False,
pre=pre,
dev=dev,
requirements_dir=requirements_directory,
index=index_url,
pypi_mirror=pypi_mirror,
use_constraint=True,
extra_pip_args=extra_pip_args,
)
if c.returncode:
err.print(
"{} An error occurred while installing {}!".format(
click.style("Error: ", fg="red", bold=True),
click.style(pkg_line, fg="green"),
),
)
err.print(f"Error text: {c.stdout}")
err.print(click.style(format_pip_error(c.stderr), fg="cyan"))
if project.s.is_verbose():
err.print(click.style(format_pip_output(c.stdout), fg="cyan"))
if "setup.py egg_info" in c.stderr:
err.print(
"This is likely caused by a bug in {}. "
"Report this to its maintainers.".format(
click.style(pkg_requirement.name, fg="green")
)
)
err.print(
environments.PIPENV_SPINNER_FAIL_TEXT.format(
"Installation Failed"
)
)
sys.exit(1)
except (ValueError, RuntimeError) as e:
err.print("{}: {}".format(click.style("WARNING", fg="red"), e))
err.print(
environments.PIPENV_SPINNER_FAIL_TEXT.format(
"Installation Failed",
)
)
sys.exit(1)
# Warn if --editable wasn't passed.
if (
pkg_requirement.is_vcs
and not pkg_requirement.editable
and not project.s.PIPENV_RESOLVE_VCS
):
err.print(
"{}: You installed a VCS dependency in non-editable mode. "
"This will work fine, but sub-dependencies will not be resolved by {}."
"\n To enable this sub-dependency functionality, specify that this dependency is editable."
"".format(
click.style("Warning", fg="red", bold=True),
click.style("$ pipenv lock", fg="yellow"),
)
)
if categories:
pipfile_sections = ""
for c in categories:
pipfile_sections += f"[{c}]"
elif dev:
pipfile_sections = "[dev-packages]"
else:
pipfile_sections = "[packages]"
st.console.print(
f"[bold]Adding [green]{pkg_requirement.name}[/green][/bold] to Pipfile's [yellow]\\{pipfile_sections}[/yellow] ..."
)
# Add the package to the Pipfile.
if index_url:
index_name = project.add_index_to_pipfile(
index_url, verify_ssl=index_url.startswith("https:")
)
pkg_requirement.index = index_name
try:
if categories:
for category in categories:
project.add_package_to_pipfile(pkg_requirement, dev, category)
else:
project.add_package_to_pipfile(pkg_requirement, dev)
except ValueError:
import traceback
err.print(
"{} {}".format(
click.style("Error:", fg="red", bold=True),
traceback.format_exc(),
)
)
err.print(
environments.PIPENV_SPINNER_FAIL_TEXT.format(
"Failed adding package to Pipfile"
)
)
# ok has a nice v in front, should do something similir with rich
st.console.print(
environments.PIPENV_SPINNER_OK_TEXT.format("Installation Succeeded")
)
# Update project settings with pre preference.
if pre:
project.update_settings({"allow_prereleases": pre})
do_init(
project,
dev=dev,
system=system,
allow_global=system,
keep_outdated=keep_outdated,
requirements_dir=requirements_directory,
deploy=deploy,
pypi_mirror=pypi_mirror,
skip_lock=skip_lock,
extra_pip_args=extra_pip_args,
categories=categories,
)
sys.exit(0)
def do_sync(
project,
dev=False,
python=None,
bare=False,
dont_upgrade=False,
user=False,
clear=False,
unused=False,
pypi_mirror=None,
system=False,
deploy=False,
extra_pip_args=None,
categories=None,
):
# The lock file needs to exist because sync won't write to it.
if not project.lockfile_exists:
raise exceptions.LockfileNotFound("Pipfile.lock")
# Ensure that virtualenv is available if not system.
ensure_project(
project,
python=python,
validate=False,
system=system,
deploy=deploy,
pypi_mirror=pypi_mirror,
clear=clear,
)
# Install everything.
requirements_dir = vistir.path.create_tracked_tempdir(
suffix="-requirements", prefix="pipenv-"
)
if system:
project.s.PIPENV_USE_SYSTEM = True
os.environ["PIPENV_USE_SYSTEM"] = "1"
do_init(
project,
dev=dev,
allow_global=system,
requirements_dir=requirements_dir,
ignore_pipfile=True, # Don't check if Pipfile and lock match.
pypi_mirror=pypi_mirror,
deploy=deploy,
system=system,
extra_pip_args=extra_pip_args,
categories=categories,
)
if not bare:
click.echo(click.style("All dependencies are now up-to-date!", fg="green"))
def do_install_dependencies(
project,
dev=False,
dev_only=False,
bare=False,
allow_global=False,
ignore_hashes=False,
skip_lock=False,
requirements_dir=None,
pypi_mirror=None,
extra_pip_args=None,
categories=None,
):
"""
Executes the installation functionality.
"""
procs = queue.Queue(maxsize=1)
if not categories:
if dev and dev_only:
categories = ["dev-packages"]
elif dev:
categories = ["packages", "dev-packages"]
else:
categories = ["packages"]
for category in categories:
# Load the lockfile if it exists, or if dev_only is being used.
if skip_lock or not project.lockfile_exists:
if not bare:
click.secho("Installing dependencies from Pipfile...", bold=True)
# skip_lock should completely bypass the lockfile (broken in 4dac1676)
lockfile = project.get_or_create_lockfile(
categories=categories, from_pipfile=True
)
else:
lockfile = project.get_or_create_lockfile(categories=categories)
if not bare:
click.secho(
"Installing dependencies from Pipfile.lock ({})...".format(
lockfile["_meta"].get("hash", {}).get("sha256")[-6:]
),
bold=True,
)
dev = dev or dev_only
deps_list = list(
lockfile.get_requirements(dev=dev, only=dev_only, categories=[category])
)
failed_deps_queue = queue.Queue()
if skip_lock:
ignore_hashes = True
editable_or_vcs_deps = [dep for dep in deps_list if (dep.editable or dep.vcs)]
normal_deps = [dep for dep in deps_list if not (dep.editable or dep.vcs)]
install_kwargs = {
"no_deps": not skip_lock,
"ignore_hashes": ignore_hashes,
"allow_global": allow_global,
"pypi_mirror": pypi_mirror,
"sequential_deps": editable_or_vcs_deps,
"extra_pip_args": extra_pip_args,
}
batch_install(
project,
normal_deps,
procs,
failed_deps_queue,
requirements_dir,
**install_kwargs,
)
if not procs.empty():
_cleanup_procs(project, procs, failed_deps_queue)
# Iterate over the hopefully-poorly-packaged dependencies...
if not failed_deps_queue.empty():
click.secho("Installing initially failed dependencies...", bold=True)
retry_list = []
while not failed_deps_queue.empty():
failed_dep = failed_deps_queue.get()
retry_list.append(failed_dep)
install_kwargs.update({"retry": False})
batch_install(
project,
retry_list,
procs,
failed_deps_queue,
requirements_dir,
**install_kwargs,
)
if not procs.empty():
_cleanup_procs(project, procs, failed_deps_queue, retry=False)
if not failed_deps_queue.empty():
failed_list = []
while not failed_deps_queue.empty():
failed_dep = failed_deps_queue.get()
failed_list.append(failed_dep)
click.echo(
click.style(
f"Failed to install some dependency or packages. "
f"The following have failed installation and attempted retry: {failed_list}",
fg="red",
),
err=True,
)
sys.exit(1)
def batch_install_iteration(
project,
deps_to_install,
sources,
procs,
failed_deps_queue,
requirements_dir,
no_deps=True,
ignore_hashes=False,
allow_global=False,
retry=True,
extra_pip_args=None,
):
from pipenv.vendor.requirementslib.models.utils import (
strip_extras_markers_from_requirement,
)
is_artifact = False
for dep in deps_to_install:
if dep.req.req:
dep.req.req = strip_extras_markers_from_requirement(dep.req.req)
if dep.markers:
dep.markers = str(strip_extras_markers_from_requirement(dep.get_markers()))
# Install the module.
if dep.is_file_or_url and (
dep.is_direct_url
or any(dep.req.uri.endswith(ext) for ext in ["zip", "tar.gz"])
):
is_artifact = True
elif dep.is_vcs:
is_artifact = True
with vistir.contextmanagers.temp_environ():
if not allow_global:
os.environ["PIP_USER"] = "0"
if "PYTHONHOME" in os.environ:
del os.environ["PYTHONHOME"]
if "GIT_CONFIG" in os.environ:
del os.environ["GIT_CONFIG"]
use_pep517 = True
if not retry and not is_artifact:
use_pep517 = False
cmds = pip_install_deps(
project,
deps=deps_to_install,
sources=sources,
allow_global=allow_global,
ignore_hashes=ignore_hashes,
no_deps=no_deps,
requirements_dir=requirements_dir,
use_pep517=use_pep517,
extra_pip_args=extra_pip_args,
)
for c in cmds:
procs.put(c)
_cleanup_procs(project, procs, failed_deps_queue, retry=retry)
def batch_install(
project,
deps_list,
procs,
failed_deps_queue,
requirements_dir,
no_deps=True,
ignore_hashes=False,
allow_global=False,
pypi_mirror=None,
retry=True,
sequential_deps=None,
extra_pip_args=None,
):
if sequential_deps is None:
sequential_deps = []
deps_to_install = deps_list[:]
deps_to_install.extend(sequential_deps)
deps_to_install = [
dep for dep in deps_to_install if not project.environment.is_satisfied(dep)
]
search_all_sources = project.settings.get("install_search_all_sources", False)
sources = get_source_list(
project,
index=None,
extra_indexes=None,
trusted_hosts=get_trusted_hosts(),
pypi_mirror=pypi_mirror,
)
if search_all_sources:
batch_install_iteration(
project,
deps_to_install,
sources,
procs,
failed_deps_queue,
requirements_dir,
no_deps=no_deps,
ignore_hashes=ignore_hashes,
allow_global=allow_global,
retry=retry,
extra_pip_args=extra_pip_args,
)
else:
# Sort the dependencies out by index -- include editable/vcs in the default group
deps_by_index = defaultdict(list)
for dependency in deps_to_install:
if dependency.index:
deps_by_index[dependency.index].append(dependency)
else:
deps_by_index[project.sources_default["name"]].append(dependency)
# Treat each index as its own pip install phase
for index_name, dependencies in deps_by_index.items():
try:
install_source = next(filter(lambda s: s["name"] == index_name, sources))
batch_install_iteration(
project,
dependencies,
[install_source],
procs,
failed_deps_queue,
requirements_dir,
no_deps=no_deps,
ignore_hashes=ignore_hashes,
allow_global=allow_global,
retry=retry,
extra_pip_args=extra_pip_args,
)
except StopIteration:
click.secho(
f"Unable to find {index_name} in sources, please check dependencies: {dependencies}",
fg="red",
bold=True,
)
sys.exit(1)
def _cleanup_procs(project, procs, failed_deps_queue, retry=True):
while not procs.empty():
c = procs.get()
try:
out, err = c.communicate()
except AttributeError:
out, err = c.stdout, c.stderr
failed = c.returncode != 0
if project.s.is_verbose():
click.secho(out.strip() or err.strip(), fg="yellow")
# The Installation failed...
if failed:
deps = getattr(c, "deps", {}).copy()
for dep in deps:
# If there is a mismatch in installed locations or the install fails
# due to wrongful disabling of pep517, we should allow for
# additional passes at installation
if "does not match installed location" in err:
project.environment.expand_egg_links()
click.echo(
"{}".format(
click.style(
"Failed initial installation: Failed to overwrite existing "
"package, likely due to path aliasing. Expanding and trying "
"again!",
fg="yellow",
)
)
)
if dep:
dep.use_pep517 = True
elif "Disabling PEP 517 processing is invalid" in err:
if dep:
dep.use_pep517 = True
elif not retry:
# The Installation failed...
# We echo both c.stdout and c.stderr because pip returns error details on out.
err = err.strip().splitlines() if err else []
out = out.strip().splitlines() if out else []
err_lines = [line for message in [out, err] for line in message]
# Return the subprocess' return code.
raise exceptions.InstallError(deps, extra=err_lines)
else:
# Alert the user.
if dep:
dep.use_pep517 = False
click.echo(
"{} {}! Will try again.".format(
click.style("An error occurred while installing", fg="red"),
click.style(dep.as_line() if dep else "", fg="green"),
),
err=True,
)
# Save the Failed Dependency for later.
failed_deps_queue.put(dep)
def do_init(
project,
dev=False,
dev_only=False,
allow_global=False,
ignore_pipfile=False,
skip_lock=False,
system=False,
deploy=False,
pre=False,
keep_outdated=False,
requirements_dir=None,
pypi_mirror=None,
extra_pip_args=None,
categories=None,
):
"""Executes the init functionality."""
python = None
if project.s.PIPENV_PYTHON is not None:
python = project.s.PIPENV_PYTHON
elif project.s.PIPENV_DEFAULT_PYTHON_VERSION is not None:
python = project.s.PIPENV_DEFAULT_PYTHON_VERSION
if categories is None:
categories = []
if not system and not project.s.PIPENV_USE_SYSTEM:
if not project.virtualenv_exists:
try:
do_create_virtualenv(project, python=python, pypi_mirror=pypi_mirror)
except KeyboardInterrupt:
cleanup_virtualenv(project, bare=False)
sys.exit(1)
# Ensure the Pipfile exists.
if not deploy:
ensure_pipfile(project, system=system)
if not requirements_dir:
requirements_dir = vistir.path.create_tracked_tempdir(
suffix="-requirements", prefix="pipenv-"
)
# Write out the lockfile if it doesn't exist, but not if the Pipfile is being ignored
if (project.lockfile_exists and not ignore_pipfile) and not skip_lock:
old_hash = project.get_lockfile_hash()
new_hash = project.calculate_pipfile_hash()
if new_hash != old_hash:
if deploy:
click.secho(
"Your Pipfile.lock ({}) is out of date. Expected: ({}).".format(
old_hash[-6:], new_hash[-6:]
),
fg="red",
)
raise exceptions.DeployException
elif (system or allow_global) and not (project.s.PIPENV_VIRTUALENV):
click.secho(
"Pipfile.lock ({}) out of date, but installation "
"uses {} re-building lockfile must happen in "
"isolation. Please rebuild lockfile in a virtualenv. "
"Continuing anyway...".format(old_hash[-6:], "--system"),
fg="yellow",
err=True,
)
else:
if old_hash:
msg = "Pipfile.lock ({0}) out of date, updating to ({1})..."
else:
msg = "Pipfile.lock is corrupt, replaced with ({1})..."
click.secho(
msg.format(old_hash[-6:], new_hash[-6:]),
fg="yellow",
bold=True,
err=True,
)
do_lock(
project,
system=system,
pre=pre,
keep_outdated=keep_outdated,
write=True,
pypi_mirror=pypi_mirror,
categories=categories,
)
# Write out the lockfile if it doesn't exist.
if not project.lockfile_exists and not skip_lock:
# Unless we're in a virtualenv not managed by pipenv, abort if we're
# using the system's python.
if (system or allow_global) and not (project.s.PIPENV_VIRTUALENV):
raise exceptions.PipenvOptionsError(
"--system",
"--system is intended to be used for Pipfile installation, "
"not installation of specific packages. Aborting.\n"
"See also: --deploy flag.",
)
else:
click.secho(
"Pipfile.lock not found, creating...",
bold=True,
err=True,
)
do_lock(
project,
system=system,
pre=pre,
keep_outdated=keep_outdated,
write=True,
pypi_mirror=pypi_mirror,
categories=categories,
)
do_install_dependencies(
project,
dev=dev,
dev_only=dev_only,
allow_global=allow_global,
skip_lock=skip_lock,
requirements_dir=requirements_dir,
pypi_mirror=pypi_mirror,
extra_pip_args=extra_pip_args,
categories=categories,
)
# Hint the user what to do to activate the virtualenv.
if not allow_global and not deploy and "PIPENV_ACTIVE" not in os.environ:
click.echo(
"To activate this project's virtualenv, run {}.\n"
"Alternatively, run a command "
"inside the virtualenv with {}.".format(
click.style("pipenv shell", fg="yellow"),
click.style("pipenv run", fg="yellow"),
)
)
+144
View File
@@ -0,0 +1,144 @@
from pipenv import exceptions
from pipenv.patched.pip._vendor.packaging.utils import canonicalize_name
from pipenv.utils.dependencies import (
get_lockfile_section_using_pipfile_category,
get_pipfile_category_using_lockfile_section,
is_pinned,
)
from pipenv.vendor import click
def do_lock(
project,
ctx=None,
system=False,
clear=False,
pre=False,
keep_outdated=False,
write=True,
pypi_mirror=None,
categories=None,
):
"""Executes the freeze functionality."""
cached_lockfile = {}
if not pre:
pre = project.settings.get("allow_prereleases")
if keep_outdated:
if not project.lockfile_exists:
raise exceptions.PipenvOptionsError(
"--keep-outdated",
ctx=ctx,
message="Pipfile.lock must exist to use --keep-outdated!",
)
cached_lockfile = project.lockfile_content
# Cleanup lockfile.
if not categories:
lockfile_categories = project.get_package_categories(for_lockfile=True)
else:
lockfile_categories = categories.copy()
if "dev-packages" in categories:
lockfile_categories.remove("dev-packages")
lockfile_categories.insert(0, "develop")
if "packages" in categories:
lockfile_categories.remove("packages")
lockfile_categories.insert(0, "default")
# Create the lockfile.
lockfile = project._lockfile(categories=lockfile_categories)
for category in lockfile_categories:
for k, v in lockfile.get(category, {}).copy().items():
if not hasattr(v, "keys"):
del lockfile[category][k]
# Resolve package to generate constraints before resolving other categories
for category in lockfile_categories:
pipfile_category = get_pipfile_category_using_lockfile_section(category)
if project.pipfile_exists:
packages = project.parsed_pipfile.get(pipfile_category, {})
else:
packages = project.get_pipfile_section(pipfile_category)
if write:
# Alert the user of progress.
click.echo(
"{} {} {}".format(
click.style("Locking"),
click.style("[{}]".format(pipfile_category), fg="yellow"),
click.style("dependencies..."),
),
err=True,
)
# Prune old lockfile category as new one will be created.
if not keep_outdated:
try:
del lockfile[category]
except KeyError:
pass
from pipenv.utils.resolver import venv_resolve_deps
# Mutates the lockfile
venv_resolve_deps(
packages,
which=project._which,
project=project,
category=pipfile_category,
clear=clear,
pre=pre,
allow_global=system,
pypi_mirror=pypi_mirror,
pipfile=packages,
lockfile=lockfile,
keep_outdated=keep_outdated,
)
# Support for --keep-outdated...
if keep_outdated:
for category_name in project.get_package_categories():
category = project.get_pipfile_section(category_name)
lockfile_section = get_lockfile_section_using_pipfile_category(category_name)
for package_specified in category.keys():
if not is_pinned(category[package_specified]):
canonical_name = canonicalize_name(package_specified)
if canonical_name in cached_lockfile[lockfile_section]:
lockfile[lockfile_section][canonical_name] = cached_lockfile[
lockfile_section
][canonical_name].copy()
packages = set(cached_lockfile[lockfile_section].keys())
new_lockfile = set(lockfile[lockfile_section].keys())
missing = packages - new_lockfile
for missing_pkg in missing:
lockfile[lockfile_section][missing_pkg] = cached_lockfile[
lockfile_section
][missing_pkg].copy()
# Overwrite any category packages with default packages.
for category in lockfile_categories:
if category == "default":
pass
if lockfile.get(category):
lockfile[category].update(
overwrite_with_default(lockfile.get("default", {}), lockfile[category])
)
if write:
lockfile.update({"_meta": project.get_lockfile_meta()})
project.write_lockfile(lockfile)
click.echo(
"{}".format(
click.style(
"Updated Pipfile.lock ({})!".format(project.get_lockfile_hash()),
bold=True,
)
),
err=True,
)
else:
return lockfile
def overwrite_with_default(default, dev):
dev_keys = set(list(dev.keys()))
prod_keys = set(list(default.keys()))
for pkg in dev_keys & prod_keys:
dev[pkg] = default[pkg]
return dev
+89
View File
@@ -0,0 +1,89 @@
import sys
from pipenv.routines.lock import do_lock
from pipenv.utils.dependencies import pep423_name
from pipenv.vendor import click
def do_outdated(project, pypi_mirror=None, pre=False, clear=False):
# TODO: Allow --skip-lock here?
from collections import namedtuple
from collections.abc import Mapping
from pipenv.patched.pip._vendor.packaging.utils import canonicalize_name
from pipenv.vendor.requirementslib.models.requirements import Requirement
from pipenv.vendor.requirementslib.models.utils import get_version
packages = {}
package_info = namedtuple("PackageInfo", ["name", "installed", "available"])
installed_packages = project.environment.get_installed_packages()
outdated_packages = {
canonicalize_name(pkg.project_name): package_info(
pkg.project_name, pkg.parsed_version, pkg.latest_version
)
for pkg in project.environment.get_outdated_packages()
}
reverse_deps = {
canonicalize_name(name): deps
for name, deps in project.environment.reverse_dependencies().items()
}
for result in installed_packages:
dep = Requirement.from_line(str(result.as_requirement()))
packages.update(dep.as_pipfile())
updated_packages = {}
lockfile = do_lock(
project, clear=clear, pre=pre, write=False, pypi_mirror=pypi_mirror
)
for category in project.get_package_categories(for_lockfile=True):
for package in lockfile.get(category, []):
try:
updated_packages[package] = lockfile[category][package]["version"]
except KeyError:
pass
outdated = []
skipped = []
for package in packages:
norm_name = pep423_name(package)
if norm_name in updated_packages:
if updated_packages[norm_name] != packages[package]:
outdated.append(
package_info(package, updated_packages[norm_name], packages[package])
)
elif canonicalize_name(package) in outdated_packages:
skipped.append(outdated_packages[canonicalize_name(package)])
for package, old_version, new_version in skipped:
for category in project.get_package_categories():
name_in_pipfile = project.get_package_name_in_pipfile(
package, category=category
)
if name_in_pipfile:
required = ""
version = get_version(
project.get_pipfile_section(category)[name_in_pipfile]
)
rdeps = reverse_deps.get(canonicalize_name(package))
if isinstance(rdeps, Mapping) and "required" in rdeps:
required = " {} required".format(rdeps["required"])
if version:
pipfile_version_text = f" ({version} set in Pipfile)"
else:
pipfile_version_text = " (Unpinned in Pipfile)"
click.secho(
"Skipped Update of Package {!s}: {!s} installed,{!s}{!s}, "
"{!s} available.".format(
package, old_version, required, pipfile_version_text, new_version
),
fg="yellow",
err=True,
)
if not outdated:
click.echo(click.style("All packages are up to date!", fg="green", bold=True))
sys.exit(0)
for package, new_version, old_version in outdated:
click.echo(
"Package {!r} out-of-date: {!r} installed, {!r} available.".format(
package, old_version, new_version
)
)
sys.exit(bool(outdated))
+170
View File
@@ -0,0 +1,170 @@
import os
import subprocess
import sys
from os.path import expandvars
from pipenv import environments
from pipenv.utils.project import ensure_project
from pipenv.utils.shell import cmd_list_to_shell, system_which
from pipenv.vendor import click
def do_shell(project, python=False, fancy=False, shell_args=None, pypi_mirror=None):
# Ensure that virtualenv is available.
ensure_project(
project,
python=python,
validate=False,
pypi_mirror=pypi_mirror,
)
# Support shell compatibility mode.
if project.s.PIPENV_SHELL_FANCY:
fancy = True
from pipenv.shells import choose_shell
shell = choose_shell(project)
click.echo("Launching subshell in virtual environment...", err=True)
fork_args = (
project.virtualenv_location,
project.project_directory,
shell_args,
)
# Set an environment variable, so we know we're in the environment.
# Only set PIPENV_ACTIVE after finishing reading virtualenv_location
# otherwise its value will be changed
os.environ["PIPENV_ACTIVE"] = "1"
if fancy:
shell.fork(*fork_args)
return
try:
shell.fork_compat(*fork_args)
except (AttributeError, ImportError):
click.echo(
"Compatibility mode not supported. "
"Trying to continue as well-configured shell...",
err=True,
)
shell.fork(*fork_args)
def do_run(project, command, args, python=False, pypi_mirror=None):
"""Attempt to run command either pulling from project or interpreting as executable.
Args are appended to the command in [scripts] section of project if found.
"""
from pipenv.cmdparse import ScriptEmptyError
env = os.environ.copy()
# Ensure that virtualenv is available.
ensure_project(
project,
python=python,
validate=False,
pypi_mirror=pypi_mirror,
)
path = env.get("PATH", "")
if project.virtualenv_location:
new_path = os.path.join(
project.virtualenv_location, "Scripts" if os.name == "nt" else "bin"
)
paths = path.split(os.pathsep)
paths.insert(0, new_path)
path = os.pathsep.join(paths)
env["VIRTUAL_ENV"] = project.virtualenv_location
env["PATH"] = path
# Set an environment variable, so we know we're in the environment.
# Only set PIPENV_ACTIVE after finishing reading virtualenv_location
# such as in inline_activate_virtual_environment
# otherwise its value will be changed
env["PIPENV_ACTIVE"] = "1"
try:
script = project.build_script(command, args)
cmd_string = cmd_list_to_shell([script.command] + script.args)
if project.s.is_verbose():
click.echo(click.style(f"$ {cmd_string}"), err=True)
except ScriptEmptyError:
click.echo("Can't run script {0!r}-it's empty?", err=True)
run_args = [project, script]
run_kwargs = {"env": env}
# We're using `do_run_nt` on CI (even if we're running on a non-nt machine)
# as a workaround for https://github.com/pypa/pipenv/issues/4909.
if os.name == "nt" or environments.PIPENV_IS_CI:
run_fn = do_run_nt
else:
run_fn = do_run_posix
run_kwargs.update({"command": command})
run_fn(*run_args, **run_kwargs)
def do_run_posix(project, script, command, env):
path = env.get("PATH")
command_path = system_which(script.command, path=path)
if not command_path:
if project.has_script(command):
click.echo(
"{}: the command {} (from {}) could not be found within {}."
"".format(
click.style("Error", fg="red", bold=True),
click.style(script.command, fg="yellow"),
click.style(command, bold=True),
click.style("PATH", bold=True),
),
err=True,
)
else:
click.echo(
"{}: the command {} could not be found within {} or Pipfile's {}."
"".format(
click.style("Error", fg="red", bold=True),
click.style(command, fg="yellow"),
click.style("PATH", bold=True),
click.style("[scripts]", bold=True),
),
err=True,
)
sys.exit(1)
os.execve(
command_path,
[command_path, *(os.path.expandvars(arg) for arg in script.args)],
env,
)
def do_run_nt(project, script, env):
p = _launch_windows_subprocess(script, env)
p.communicate()
sys.exit(p.returncode)
def _launch_windows_subprocess(script, env):
path = env.get("PATH", "")
command = system_which(script.command, path=path)
options = {"universal_newlines": True, "env": env}
script.cmd_args[1:] = [expandvars(arg) for arg in script.args]
# Command not found, maybe this is a shell built-in?
if not command:
return subprocess.Popen(script.cmdify(), shell=True, **options)
# Try to use CreateProcess directly if possible. Specifically catch
# Windows error 193 "Command is not a valid Win32 application" to handle
# a "command" that is non-executable. See pypa/pipenv#2727.
try:
return subprocess.Popen([command] + script.args, **options)
except OSError as e:
if e.winerror != 193:
raise
# Try shell mode to use Windows's file association for file launch.
return subprocess.Popen(script.cmdify(), shell=True, **options)
+220
View File
@@ -0,0 +1,220 @@
import shutil
import sys
from pipenv import exceptions
from pipenv.patched.pip._internal.build_env import get_runnable_pip
from pipenv.patched.pip._vendor.packaging.utils import canonicalize_name
from pipenv.routines.lock import do_lock
from pipenv.utils.dependencies import (
get_canonical_names,
get_lockfile_section_using_pipfile_category,
get_pipfile_category_using_lockfile_section,
pep423_name,
)
from pipenv.utils.processes import run_command, subprocess_run
from pipenv.utils.project import ensure_project
from pipenv.utils.requirements import BAD_PACKAGES
from pipenv.utils.shell import cmd_list_to_shell, project_python
from pipenv.vendor import click
from pipenv.vendor.requirementslib import Requirement
def do_uninstall(
project,
packages=None,
editable_packages=None,
python=False,
system=False,
lock=False,
all_dev=False,
all=False,
keep_outdated=False,
pypi_mirror=None,
ctx=None,
categories=None,
):
# Automatically use an activated virtualenv.
if project.s.PIPENV_USE_SYSTEM:
system = True
# Ensure that virtualenv is available.
ensure_project(project, python=python, pypi_mirror=pypi_mirror)
# Uninstall all dependencies, if --all was provided.
if not any([packages, editable_packages, all_dev, all]):
raise exceptions.PipenvUsageError("No package provided!", ctx=ctx)
if not categories:
categories = project.get_package_categories(for_lockfile=True)
editable_pkgs = [
Requirement.from_line(f"-e {p}").name for p in editable_packages if p
]
packages += editable_pkgs
package_names = {p for p in packages if p}
package_map = {canonicalize_name(p): p for p in packages if p}
installed_package_names = project.installed_package_names
if project.lockfile_exists:
project_pkg_names = project.lockfile_package_names
else:
project_pkg_names = project.pipfile_package_names
# Uninstall [dev-packages], if --dev was provided.
if all_dev:
if (
"dev-packages" not in project.parsed_pipfile
and not project_pkg_names["develop"]
):
click.echo(
click.style(
"No {} to uninstall.".format(
click.style("[dev-packages]", fg="yellow")
),
bold=True,
)
)
return
click.secho(
click.style(
"Un-installing {}...".format(click.style("[dev-packages]", fg="yellow")),
bold=True,
)
)
preserve_packages = set()
dev_packages = set()
for category in project.get_package_categories(for_lockfile=True):
if category == "develop":
dev_packages |= set(project_pkg_names[category])
else:
preserve_packages |= set(project_pkg_names[category])
package_names = dev_packages - preserve_packages
# Remove known "bad packages" from the list.
bad_pkgs = get_canonical_names(BAD_PACKAGES)
ignored_packages = bad_pkgs & set(list(package_map.keys()))
for ignored_pkg in get_canonical_names(ignored_packages):
if project.s.is_verbose():
click.echo(f"Ignoring {ignored_pkg}.", err=True)
package_names.discard(package_map[ignored_pkg])
used_packages = project_pkg_names["combined"] & installed_package_names
failure = False
if all:
click.echo(
click.style(
"Un-installing all {} and {}...".format(
click.style("[dev-packages]", fg="yellow"),
click.style("[packages]", fg="yellow"),
),
bold=True,
)
)
do_purge(project, bare=False, allow_global=system)
sys.exit(0)
selected_pkg_map = {canonicalize_name(p): p for p in package_names}
packages_to_remove = [
package_name
for normalized, package_name in selected_pkg_map.items()
if normalized in (used_packages - bad_pkgs)
]
lockfile = project.get_or_create_lockfile(categories=categories)
for category in categories:
category = get_lockfile_section_using_pipfile_category(category)
for normalized_name, package_name in selected_pkg_map.items():
if normalized_name in project.lockfile_content[category]:
click.echo(
"{} {} {} {}".format(
click.style("Removing", fg="cyan"),
click.style(package_name, fg="green"),
click.style("from", fg="cyan"),
click.style("Pipfile.lock...", fg="white"),
)
)
if normalized_name in lockfile[category]:
del lockfile[category][normalized_name]
lockfile.write()
pipfile_category = get_pipfile_category_using_lockfile_section(category)
if project.remove_package_from_pipfile(
package_name, category=pipfile_category
):
click.secho(
f"Removed {package_name} from Pipfile category {pipfile_category}",
fg="green",
)
for normalized_name, package_name in selected_pkg_map.items():
still_remains = False
for category in project.get_package_categories():
if project.get_package_name_in_pipfile(normalized_name, category=category):
still_remains = True
if not still_remains:
# Uninstall the package.
if package_name in packages_to_remove:
click.secho(
f"Uninstalling {click.style(package_name)}...",
fg="green",
bold=True,
)
with project.environment.activated():
cmd = [
project_python(project, system=system),
get_runnable_pip(),
"uninstall",
package_name,
"-y",
]
c = run_command(cmd, is_verbose=project.s.is_verbose())
click.secho(c.stdout, fg="cyan")
if c.returncode != 0:
failure = True
if lock:
do_lock(
project, system=system, keep_outdated=keep_outdated, pypi_mirror=pypi_mirror
)
sys.exit(int(failure))
def do_purge(project, bare=False, downloads=False, allow_global=False):
"""Executes the purge functionality."""
if downloads:
if not bare:
click.secho("Clearing out downloads directory...", bold=True)
shutil.rmtree(project.download_location)
return
# Remove comments from the output, if any.
installed = {
pep423_name(pkg.project_name)
for pkg in project.environment.get_installed_packages()
}
bad_pkgs = {pep423_name(pkg) for pkg in BAD_PACKAGES}
# Remove setuptools, pip, etc from targets for removal
to_remove = installed - bad_pkgs
# Skip purging if there is no packages which needs to be removed
if not to_remove:
if not bare:
click.echo("Found 0 installed package, skip purging.")
click.secho("Environment now purged and fresh!", fg="green")
return installed
if not bare:
click.echo(f"Found {len(to_remove)} installed package(s), purging...")
command = [
project_python(project, system=allow_global),
get_runnable_pip(),
"uninstall",
"-y",
] + list(to_remove)
if project.s.is_verbose():
click.echo(f"$ {cmd_list_to_shell(command)}")
c = subprocess_run(command)
if c.returncode != 0:
raise exceptions.UninstallError(
installed, cmd_list_to_shell(command), c.stdout + c.stderr, c.returncode
)
if not bare:
click.secho(c.stdout, fg="cyan")
click.secho("Environment now purged and fresh!", fg="green")
return installed
+65
View File
@@ -0,0 +1,65 @@
from pipenv.vendor import click
def format_help(help):
"""Formats the help string."""
help = help.replace("Options:", str(click.style("Options:", bold=True)))
help = help.replace(
"Usage: pipenv", str("Usage: {}".format(click.style("pipenv", bold=True)))
)
help = help.replace(" check", str(click.style(" check", fg="red", bold=True)))
help = help.replace(" clean", str(click.style(" clean", fg="red", bold=True)))
help = help.replace(" graph", str(click.style(" graph", fg="red", bold=True)))
help = help.replace(
" install", str(click.style(" install", fg="magenta", bold=True))
)
help = help.replace(" lock", str(click.style(" lock", fg="green", bold=True)))
help = help.replace(" open", str(click.style(" open", fg="red", bold=True)))
help = help.replace(" run", str(click.style(" run", fg="yellow", bold=True)))
help = help.replace(" shell", str(click.style(" shell", fg="yellow", bold=True)))
help = help.replace(
" scripts", str(click.style(" scripts", fg="yellow", bold=True))
)
help = help.replace(" sync", str(click.style(" sync", fg="green", bold=True)))
help = help.replace(
" uninstall", str(click.style(" uninstall", fg="magenta", bold=True))
)
help = help.replace(" update", str(click.style(" update", fg="green", bold=True)))
additional_help = """
Usage Examples:
Create a new project using Python 3.7, specifically:
$ {}
Remove project virtualenv (inferred from current directory):
$ {}
Install all dependencies for a project (including dev):
$ {}
Create a lockfile containing pre-releases:
$ {}
Show a graph of your installed dependencies:
$ {}
Check your installed dependencies for security vulnerabilities:
$ {}
Install a local setup.py into your virtual environment/Pipfile:
$ {}
Use a lower-level pip command:
$ {}
Commands:""".format(
click.style("pipenv --python 3.7", fg="yellow"),
click.style("pipenv --rm", fg="yellow"),
click.style("pipenv install --dev", fg="yellow"),
click.style("pipenv lock --pre", fg="yellow"),
click.style("pipenv graph", fg="yellow"),
click.style("pipenv check", fg="yellow"),
click.style("pipenv install -e .", fg="yellow"),
click.style("pipenv run pip freeze", fg="yellow"),
)
help = help.replace("Commands:", additional_help)
return help
+16
View File
@@ -37,3 +37,19 @@ def load_dot_env(project, as_dict=False, quiet=False):
dotenv.load_dotenv(dotenv_file, override=True)
project.s = environments.Setting()
def ensure_environment():
# Skip this on Windows...
if os.name != "nt":
if "LANG" not in os.environ:
click.echo(
"{}: the environment variable {} is not set!"
"\nWe recommend setting this in {} (or equivalent) for "
"proper expected behavior.".format(
click.style("Warning", fg="red", bold=True),
click.style("LANG", bold=True),
click.style("~/.profile", fg="green"),
),
err=True,
)
+431
View File
@@ -0,0 +1,431 @@
import logging
import os
import tempfile
from pathlib import Path
from typing import List, Optional
from pipenv.patched.pip._internal.build_env import get_runnable_pip
from pipenv.project import Project
from pipenv.utils.dependencies import get_constraints_from_deps, prepare_constraint_file
from pipenv.utils.indexes import get_source_list, prepare_pip_source_args
from pipenv.utils.processes import subprocess_run
from pipenv.utils.shell import cmd_list_to_shell, normalize_path, project_python
from pipenv.vendor import click, vistir
from pipenv.vendor.requirementslib import Requirement
def format_pip_output(out, r=None):
def gen(out):
for line in out.split("\n"):
# Remove requirements file information from pip9 output.
if "(from -r" in line:
yield line[: line.index("(from -r")]
else:
yield line
out = "\n".join([line for line in gen(out)])
return out
def format_pip_error(error):
error = error.replace("Expected", str(click.style("Expected", fg="green", bold=True)))
error = error.replace("Got", str(click.style("Got", fg="red", bold=True)))
error = error.replace(
"THESE PACKAGES DO NOT MATCH THE HASHES FROM THE REQUIREMENTS FILE",
str(
click.style(
"THESE PACKAGES DO NOT MATCH THE HASHES FROM Pipfile.lock!",
fg="red",
bold=True,
)
),
)
error = error.replace(
"someone may have tampered with them",
str(click.style("someone may have tampered with them", fg="red")),
)
error = error.replace("option to pip install", "option to 'pipenv install'")
return error
def pip_download(project, package_name):
cache_dir = Path(project.s.PIPENV_CACHE_DIR)
pip_config = {
"PIP_CACHE_DIR": cache_dir.as_posix(),
"PIP_WHEEL_DIR": cache_dir.joinpath("wheels").as_posix(),
"PIP_DESTINATION_DIR": cache_dir.joinpath("pkgs").as_posix(),
}
for source in project.sources:
cmd = [
project_python(project),
get_runnable_pip(),
"download",
package_name,
"-i",
source["url"],
"-d",
project.download_location,
]
c = subprocess_run(cmd, env=pip_config)
if c.returncode == 0:
break
return c
def pip_install_deps(
project,
deps,
sources,
allow_global=False,
ignore_hashes=False,
no_deps=False,
selective_upgrade=False,
requirements_dir=None,
use_pep517=True,
extra_pip_args: Optional[List] = None,
):
if not allow_global:
src_dir = os.getenv(
"PIP_SRC", os.getenv("PIP_SRC_DIR", project.virtualenv_src_location)
)
else:
src_dir = os.getenv("PIP_SRC", os.getenv("PIP_SRC_DIR"))
if not requirements_dir:
requirements_dir = vistir.path.create_tracked_tempdir(
prefix="pipenv", suffix="requirements"
)
standard_requirements = tempfile.NamedTemporaryFile(
prefix="pipenv-", suffix="-hashed-reqs.txt", dir=requirements_dir, delete=False
)
editable_requirements = tempfile.NamedTemporaryFile(
prefix="pipenv-", suffix="-reqs.txt", dir=requirements_dir, delete=False
)
for requirement in deps:
ignore_hash = ignore_hashes
vcs_or_editable = (
requirement.is_vcs
or requirement.vcs
or requirement.editable
or (requirement.is_file_or_url and not requirement.hashes)
)
if vcs_or_editable:
ignore_hash = True
if requirement and vcs_or_editable:
requirement.index = None
line = requirement.line_instance.get_line(
with_prefix=True,
with_hashes=not ignore_hash,
with_markers=True,
as_list=False,
)
if project.s.is_verbose():
click.echo(
f"Writing supplied requirement line to temporary file: {line!r}",
err=True,
)
target = editable_requirements if vcs_or_editable else standard_requirements
target.write(line.encode())
target.write(b"\n")
standard_requirements.close()
editable_requirements.close()
cmds = []
files = []
standard_deps = list(
filter(
lambda d: not (
d.is_vcs or d.vcs or d.editable or (d.is_file_or_url and not d.hashes)
),
deps,
)
)
if standard_deps:
files.append(standard_requirements)
editable_deps = list(
filter(
lambda d: d.is_vcs
or d.vcs
or d.editable
or (d.is_file_or_url and not d.hashes),
deps,
)
)
if editable_deps:
files.append(editable_requirements)
for file in files:
pip_command = [
project_python(project, system=allow_global),
get_runnable_pip(),
"install",
]
pip_args = get_pip_args(
project,
pre=project.settings.get("allow_prereleases", False),
verbose=False, # When True, the subprocess fails to recognize the EOF when reading stdout.
upgrade=True,
selective_upgrade=False,
no_use_pep517=not use_pep517,
no_deps=no_deps,
extra_pip_args=extra_pip_args,
)
pip_command.extend(prepare_pip_source_args(sources))
pip_command.extend(pip_args)
pip_command.extend(["-r", normalize_path(file.name)])
if project.s.is_verbose():
msg = f"Install Phase: {'Standard Requirements' if file == standard_requirements else 'Editable Requirements'}"
click.echo(
click.style(msg, bold=True),
err=True,
)
for requirement in (
standard_deps if file == standard_requirements else editable_deps
):
click.echo(
click.style(
f"Preparing Installation of {requirement.name!r}", bold=True
),
err=True,
)
click.secho(f"$ {cmd_list_to_shell(pip_command)}", fg="cyan", err=True)
cache_dir = Path(project.s.PIPENV_CACHE_DIR)
default_exists_action = "w"
if selective_upgrade:
default_exists_action = "i"
exists_action = project.s.PIP_EXISTS_ACTION or default_exists_action
pip_config = {
"PIP_CACHE_DIR": cache_dir.as_posix(),
"PIP_WHEEL_DIR": cache_dir.joinpath("wheels").as_posix(),
"PIP_DESTINATION_DIR": cache_dir.joinpath("pkgs").as_posix(),
"PIP_EXISTS_ACTION": exists_action,
"PATH": os.environ.get("PATH"),
}
if src_dir:
if project.s.is_verbose():
click.echo(f"Using source directory: {src_dir!r}", err=True)
pip_config.update({"PIP_SRC": src_dir})
c = subprocess_run(pip_command, block=False, capture_output=True, env=pip_config)
if file == standard_requirements:
c.deps = standard_deps
else:
c.deps = editable_deps
c.env = pip_config
cmds.append(c)
if project.s.is_verbose():
while True:
line = c.stdout.readline()
if line == "":
break
if "Ignoring" in line:
click.secho(line, fg="red", err=True)
elif line:
click.secho(line, fg="yellow", err=True)
return cmds
def pip_install(
project,
requirement=None,
r=None,
allow_global=False,
ignore_hashes=False,
no_deps=False,
block=True,
index=None,
pre=False,
dev=False,
selective_upgrade=False,
requirements_dir=None,
extra_indexes=None,
pypi_mirror=None,
use_pep517=True,
use_constraint=False,
extra_pip_args: Optional[List] = None,
):
piplogger = logging.getLogger("pipenv.patched.pip._internal.commands.install")
trusted_hosts = get_trusted_hosts()
if not allow_global:
src_dir = os.getenv(
"PIP_SRC", os.getenv("PIP_SRC_DIR", project.virtualenv_src_location)
)
else:
src_dir = os.getenv("PIP_SRC", os.getenv("PIP_SRC_DIR"))
if requirement:
if requirement.editable or not requirement.hashes:
ignore_hashes = True
elif not (requirement.is_vcs or requirement.editable or requirement.vcs):
ignore_hashes = False
line = None
# Try installing for each source in project.sources.
search_all_sources = project.settings.get("install_search_all_sources", False)
if not index and requirement.index:
index = requirement.index
if index and not extra_indexes:
if search_all_sources:
extra_indexes = list(project.sources)
else: # Default: index restrictions apply during installation
extra_indexes = []
if requirement.index:
extra_indexes = list(
filter(lambda d: d.get("name") == requirement.index, project.sources)
)
if not extra_indexes:
extra_indexes = list(project.sources)
if requirement and requirement.vcs or requirement.editable:
requirement.index = None
r = write_requirement_to_file(
project,
requirement,
requirements_dir=requirements_dir,
include_hashes=not ignore_hashes,
)
sources = get_source_list(
project,
index,
extra_indexes=extra_indexes,
trusted_hosts=trusted_hosts,
pypi_mirror=pypi_mirror,
)
source_names = {src.get("name") for src in sources}
if not search_all_sources and requirement.index in source_names:
sources = list(filter(lambda d: d.get("name") == requirement.index, sources))
if r:
with open(r, "r") as fh:
if "--hash" not in fh.read():
ignore_hashes = True
if project.s.is_verbose():
piplogger.setLevel(logging.WARN)
if requirement:
click.echo(
click.style(f"Installing {requirement.name!r}", bold=True),
err=True,
)
pip_command = [
project_python(project, system=allow_global),
get_runnable_pip(),
"install",
]
pip_args = get_pip_args(
project,
pre=pre,
verbose=project.s.is_verbose(),
upgrade=True,
selective_upgrade=selective_upgrade,
no_use_pep517=not use_pep517,
no_deps=no_deps,
require_hashes=not ignore_hashes,
extra_pip_args=extra_pip_args,
)
pip_command.extend(pip_args)
if r:
pip_command.extend(["-r", normalize_path(r)])
elif line:
pip_command.extend(line)
if dev and use_constraint:
default_constraints = get_constraints_from_deps(project.packages)
constraint_filename = prepare_constraint_file(
default_constraints,
directory=requirements_dir,
sources=None,
pip_args=None,
)
pip_command.extend(["-c", normalize_path(constraint_filename)])
pip_command.extend(prepare_pip_source_args(sources))
if project.s.is_verbose():
click.echo(f"$ {cmd_list_to_shell(pip_command)}", err=True)
cache_dir = Path(project.s.PIPENV_CACHE_DIR)
default_exists_action = "w"
if selective_upgrade:
default_exists_action = "i"
exists_action = project.s.PIP_EXISTS_ACTION or default_exists_action
pip_config = {
"PIP_CACHE_DIR": cache_dir.as_posix(),
"PIP_WHEEL_DIR": cache_dir.joinpath("wheels").as_posix(),
"PIP_DESTINATION_DIR": cache_dir.joinpath("pkgs").as_posix(),
"PIP_EXISTS_ACTION": exists_action,
"PATH": os.environ.get("PATH"),
}
if src_dir:
if project.s.is_verbose():
click.echo(f"Using source directory: {src_dir!r}", err=True)
pip_config.update({"PIP_SRC": src_dir})
c = subprocess_run(pip_command, block=block, env=pip_config)
c.env = pip_config
return c
def get_pip_args(
project,
pre: bool = False,
verbose: bool = False,
upgrade: bool = False,
require_hashes: bool = False,
no_build_isolation: bool = False,
no_use_pep517: bool = False,
no_deps: bool = False,
selective_upgrade: bool = False,
src_dir: Optional[str] = None,
extra_pip_args: Optional[List] = None,
) -> List[str]:
arg_map = {
"pre": ["--pre"],
"verbose": ["--verbose"],
"upgrade": ["--upgrade"],
"require_hashes": ["--require-hashes"],
"no_build_isolation": ["--no-build-isolation"],
"no_use_pep517": ["--no-use-pep517"],
"no_deps": ["--no-deps"],
"selective_upgrade": [
"--upgrade-strategy=only-if-needed",
"--exists-action={}".format(project.s.PIP_EXISTS_ACTION or "i"),
],
"src_dir": src_dir,
}
arg_set = ["--no-input"] if project.settings.get("disable_pip_input", True) else []
for key in arg_map.keys():
if key in locals() and locals().get(key):
arg_set.extend(arg_map.get(key))
elif key == "selective_upgrade" and not locals().get(key):
arg_set.append("--exists-action=i")
for extra_pip_arg in extra_pip_args:
arg_set.append(extra_pip_arg)
return list(dict.fromkeys(arg_set))
def get_trusted_hosts():
try:
return os.environ.get("PIP_TRUSTED_HOSTS", []).split(" ")
except AttributeError:
return []
def write_requirement_to_file(
project: Project,
requirement: Requirement,
requirements_dir: Optional[str] = None,
include_hashes: bool = True,
) -> str:
if not requirements_dir:
requirements_dir = vistir.path.create_tracked_tempdir(
prefix="pipenv", suffix="requirements"
)
line = requirement.line_instance.get_line(
with_prefix=True, with_hashes=include_hashes, with_markers=True, as_list=False
)
f = tempfile.NamedTemporaryFile(
prefix="pipenv-", suffix="-requirement.txt", dir=requirements_dir, delete=False
)
if project.s.is_verbose():
click.echo(
f"Writing supplied requirement line to temporary file: {line!r}", err=True
)
f.write(line.encode())
r = f.name
f.close()
return r
+77
View File
@@ -1,5 +1,13 @@
import os
from pipenv import environments, exceptions
from pipenv.patched.pip._vendor import rich
from pipenv.utils.requirements import import_requirements
from pipenv.vendor import click
console = rich.console.Console()
err = rich.console.Console(stderr=True)
def walk_up(bottom):
"""mimic os.walk, but walk 'up' instead of down the directory tree.
@@ -45,3 +53,72 @@ def find_pipfile(max_depth=3):
if os.path.isfile(p):
return p
raise RuntimeError("No Pipfile found!")
def ensure_pipfile(project, validate=True, skip_requirements=False, system=False):
"""Creates a Pipfile for the project, if it doesn't exist."""
# Assert Pipfile exists.
python = (
project._which("python")
if not (project.s.USING_DEFAULT_PYTHON or system)
else None
)
if project.pipfile_is_empty:
# Show an error message and exit if system is passed and no pipfile exists
if system and not project.s.PIPENV_VIRTUALENV:
raise exceptions.PipenvOptionsError(
"--system",
"--system is intended to be used for pre-existing Pipfile "
"installation, not installation of specific packages. Aborting.",
)
# If there's a requirements file, but no Pipfile...
if project.requirements_exists and not skip_requirements:
requirements_dir_path = os.path.dirname(project.requirements_location)
click.echo(
"{0} found in {1} instead of {2}! Converting...".format(
click.style("requirements.txt", bold=True),
click.style(requirements_dir_path, fg="yellow", bold=True),
click.style("Pipfile", bold=True),
)
)
# Create a Pipfile...
project.create_pipfile(python=python)
with console.status(
"Importing requirements...", spinner=project.s.PIPENV_SPINNER
) as st:
# Import requirements.txt.
try:
import_requirements(project)
except Exception:
err.print(environments.PIPENV_SPINNER_FAIL_TEXT.format("Failed..."))
else:
st.console.print(
environments.PIPENV_SPINNER_OK_TEXT.format("Success!")
)
# Warn the user of side-effects.
click.echo(
"{0}: Your {1} now contains pinned versions, if your {2} did. \n"
"We recommend updating your {1} to specify the {3} version, instead."
"".format(
click.style("Warning", fg="red", bold=True),
click.style("Pipfile", bold=True),
click.style("requirements.txt", bold=True),
click.style('"*"', bold=True),
)
)
else:
click.secho("Creating a Pipfile for this project...", bold=True, err=True)
# Create the pipfile if it doesn't exist.
project.create_pipfile(python=python)
# Validate the Pipfile's contents.
if validate and project.virtualenv_exists and not project.s.PIPENV_SKIP_VALIDATION:
# Ensure that Pipfile is using proper casing.
p = project.parsed_pipfile
changed = project.ensure_proper_casing()
# Write changes out to disk.
if changed:
click.echo(
click.style("Fixing package names in Pipfile...", bold=True), err=True
)
project.write_toml(p)
+79
View File
@@ -0,0 +1,79 @@
from pipenv import exceptions
from pipenv.utils.dependencies import python_version
from pipenv.utils.pipfile import ensure_pipfile
from pipenv.utils.shell import shorten_path
from pipenv.utils.virtualenv import ensure_virtualenv
from pipenv.vendor import click
def ensure_project(
project,
python=None,
validate=True,
system=False,
warn=True,
site_packages=None,
deploy=False,
skip_requirements=False,
pypi_mirror=None,
clear=False,
):
"""Ensures both Pipfile and virtualenv exist for the project."""
# Automatically use an activated virtualenv.
if project.s.PIPENV_USE_SYSTEM or project.virtualenv_exists:
system_or_exists = True
else:
system_or_exists = system # default to False
if not project.pipfile_exists and deploy:
raise exceptions.PipfileNotFound
# Skip virtualenv creation when --system was used.
if not system_or_exists:
ensure_virtualenv(
project,
python=python,
site_packages=site_packages,
pypi_mirror=pypi_mirror,
)
if warn:
# Warn users if they are using the wrong version of Python.
if project.required_python_version:
path_to_python = project._which("python") or project._which("py")
if path_to_python and project.required_python_version not in (
python_version(path_to_python) or ""
):
click.echo(
"{}: Your Pipfile requires {} {}, "
"but you are using {} ({}).".format(
click.style("Warning", fg="red", bold=True),
click.style("python_version", bold=True),
click.style(project.required_python_version, fg="cyan"),
click.style(
python_version(path_to_python) or "unknown", fg="cyan"
),
click.style(shorten_path(path_to_python), fg="green"),
),
err=True,
)
click.echo(
" {} and rebuilding the virtual environment "
"may resolve the issue.".format(
click.style("$ pipenv --rm", fg="green")
),
err=True,
)
if not deploy:
click.echo(
" {} will surely fail."
"".format(click.style("$ pipenv check", fg="yellow")),
err=True,
)
else:
raise exceptions.DeployException
# Ensure the Pipfile exists.
ensure_pipfile(
project,
validate=validate,
skip_requirements=skip_requirements,
system=system_or_exists,
)
+85
View File
@@ -0,0 +1,85 @@
import os
import re
from pipenv.patched.pip._internal.network.session import PipSession
from pipenv.patched.pip._internal.req import parse_requirements
from pipenv.patched.pip._internal.req.constructors import (
install_req_from_parsed_requirement,
)
from pipenv.patched.pip._internal.utils.misc import split_auth_from_netloc
from pipenv.utils.indexes import parse_indexes
from pipenv.utils.internet import get_host_and_port
def import_requirements(project, r=None, dev=False):
# Parse requirements.txt file with Pip's parser.
# Pip requires a `PipSession` which is a subclass of requests.Session.
# Since we're not making any network calls, it's initialized to nothing.
if r:
assert os.path.isfile(r)
# Default path, if none is provided.
if r is None:
r = project.requirements_location
with open(r) as f:
contents = f.read()
indexes = []
trusted_hosts = []
# Find and add extra indexes.
for line in contents.split("\n"):
index, extra_index, trusted_host, _ = parse_indexes(line.strip(), strict=True)
if index:
indexes = [index]
if extra_index:
indexes.append(extra_index)
if trusted_host:
trusted_hosts.append(get_host_and_port(trusted_host))
indexes = sorted(set(indexes))
trusted_hosts = sorted(set(trusted_hosts))
reqs = [
install_req_from_parsed_requirement(f)
for f in parse_requirements(r, session=PipSession())
]
for package in reqs:
if package.name not in BAD_PACKAGES:
if package.link is not None:
if package.editable:
package_string = f"-e {package.link}"
else:
netloc, (user, pw) = split_auth_from_netloc(package.link.netloc)
safe = True
if user and not re.match(r"\${[\W\w]+}", user):
safe = False
if pw and not re.match(r"\${[\W\w]+}", pw):
safe = False
if safe:
package_string = str(package.link._url)
else:
package_string = str(package.link)
project.add_package_to_pipfile(package_string, dev=dev)
else:
project.add_package_to_pipfile(str(package.req), dev=dev)
for index in indexes:
# don't require HTTPS for trusted hosts (see: https://pip.pypa.io/en/stable/cli/pip/#cmdoption-trusted-host)
host_and_port = get_host_and_port(index)
require_valid_https = not any(
(
v in trusted_hosts
for v in (
host_and_port,
host_and_port.partition(":")[
0
], # also check if hostname without port is in trusted_hosts
)
)
)
project.add_index_to_pipfile(index, verify_ssl=require_valid_https)
project.recase_pipfile()
BAD_PACKAGES = (
"distribute",
"pip",
"pkg-resources",
"setuptools",
"wheel",
)
+13
View File
@@ -453,3 +453,16 @@ def system_which(command, path=None):
if c.returncode == 0:
result = next(iter(c.stdout.splitlines()), None)
return result
def shorten_path(location, bold=False):
"""Returns a visually shorter representation of a given system path."""
original = location
short = os.sep.join(
[s[0] if len(s) > (len("2long4")) else s for s in location.split(os.sep)]
)
short = short.split(os.sep)
short[-1] = original.split(os.sep)[-1]
if bold:
short[-1] = str(click.style(short[-1], bold=True))
return os.sep.join(short)
+443
View File
@@ -0,0 +1,443 @@
import os
import shutil
import sys
from pathlib import Path
from pipenv import environments, exceptions
from pipenv.patched.pip._vendor import rich
from pipenv.utils.dependencies import python_version
from pipenv.utils.environment import ensure_environment
from pipenv.utils.processes import subprocess_run
from pipenv.utils.shell import find_python, shorten_path
from pipenv.vendor import click
console = rich.console.Console()
err = rich.console.Console(stderr=True)
def warn_in_virtualenv(project):
# Only warn if pipenv isn't already active.
if environments.is_in_virtualenv() and not project.s.is_quiet():
click.echo(
"{}: Pipenv found itself running within a virtual environment, "
"so it will automatically use that environment, instead of "
"creating its own for any project. You can set "
"{} to force pipenv to ignore that environment and create "
"its own instead. You can set {} to suppress this "
"warning.".format(
click.style("Courtesy Notice", fg="green"),
click.style("PIPENV_IGNORE_VIRTUALENVS=1", bold=True),
click.style("PIPENV_VERBOSITY=-1", bold=True),
),
err=True,
)
def do_create_virtualenv(project, python=None, site_packages=None, pypi_mirror=None):
"""Creates a virtualenv."""
click.secho("Creating a virtualenv for this project...", bold=True, err=True)
click.echo(
"Pipfile: " + click.style(project.pipfile_location, fg="yellow", bold=True),
err=True,
)
# Default to using sys.executable, if Python wasn't provided.
using_string = "Using"
if not python:
python = sys.executable
using_string = "Using default python from"
click.echo(
"{0} {1} {3} {2}".format(
click.style(using_string, bold=True),
click.style(python, fg="yellow", bold=True),
click.style("to create virtualenv...", bold=True),
click.style(f"({python_version(python)})", fg="green"),
),
err=True,
)
if site_packages:
click.secho("Making site-packages available...", bold=True, err=True)
if pypi_mirror:
pip_config = {"PIP_INDEX_URL": pypi_mirror}
else:
pip_config = {}
error = None
with console.status(
"Creating virtual environment...", spinner=project.s.PIPENV_SPINNER
):
cmd = _create_virtualenv_cmd(project, python, site_packages=site_packages)
c = subprocess_run(cmd, env=pip_config)
click.secho(f"{c.stdout}", fg="cyan", err=True)
if c.returncode != 0:
error = (
c.stderr if project.s.is_verbose() else exceptions.prettify_exc(c.stderr)
)
err.print(
environments.PIPENV_SPINNER_FAIL_TEXT.format(
"Failed creating virtual environment"
)
)
else:
err.print(
environments.PIPENV_SPINNER_OK_TEXT.format(
"Successfully created virtual environment!"
)
)
if error is not None:
raise exceptions.VirtualenvCreationException(
extra=click.style(f"{error}", fg="red")
)
# Associate project directory with the environment.
project_file_name = os.path.join(project.virtualenv_location, ".project")
with open(project_file_name, "w") as f:
f.write(project.project_directory)
from pipenv.environment import Environment
sources = project.pipfile_sources()
# project.get_location_for_virtualenv is only for if we are creating a new virtualenv
# whereas virtualenv_location is for the current path to the runtime
project._environment = Environment(
prefix=project.virtualenv_location,
is_venv=True,
sources=sources,
pipfile=project.parsed_pipfile,
project=project,
)
# Say where the virtualenv is.
do_where(project, virtualenv=True, bare=False)
def _create_virtualenv_cmd(project, python, site_packages=False):
cmd = [
Path(sys.executable).absolute().as_posix(),
"-m",
"virtualenv",
]
if project.s.PIPENV_VIRTUALENV_CREATOR:
cmd.append(f"--creator={project.s.PIPENV_VIRTUALENV_CREATOR}")
cmd.append(f"--prompt={project.name}")
cmd.append(f"--python={python}")
cmd.append(project.get_location_for_virtualenv())
if project.s.PIPENV_VIRTUALENV_COPIES:
cmd.append("--copies")
# Pass site-packages flag to virtualenv, if desired...
if site_packages:
cmd.append("--system-site-packages")
return cmd
def ensure_virtualenv(project, python=None, site_packages=None, pypi_mirror=None):
"""Creates a virtualenv, if one doesn't exist."""
def abort():
sys.exit(1)
if not project.virtualenv_exists:
try:
# Ensure environment variables are set properly.
ensure_environment()
# Ensure Python is available.
python = ensure_python(project, python=python)
if python is not None and not isinstance(python, str):
python = python.path.as_posix()
# Create the virtualenv.
# Abort if --system (or running in a virtualenv).
if project.s.PIPENV_USE_SYSTEM:
click.secho(
"You are attempting to recreate a virtualenv that "
"Pipenv did not create. Aborting.",
fg="red",
)
sys.exit(1)
do_create_virtualenv(
project,
python=python,
site_packages=site_packages,
pypi_mirror=pypi_mirror,
)
except KeyboardInterrupt:
# If interrupted, cleanup the virtualenv.
cleanup_virtualenv(project, bare=False)
sys.exit(1)
# If --python or was passed...
elif (python) or (site_packages is not None):
project.s.USING_DEFAULT_PYTHON = False
# Ensure python is installed before deleting existing virtual env
python = ensure_python(project, python=python)
if python is not None and not isinstance(python, str):
python = python.path.as_posix()
click.secho("Virtualenv already exists!", fg="red", err=True)
# If VIRTUAL_ENV is set, there is a possibility that we are
# going to remove the active virtualenv that the user cares
# about, so confirm first.
if "VIRTUAL_ENV" in os.environ:
if not (
project.s.PIPENV_YES
or click.confirm("Use existing virtualenv?", default=True)
):
abort()
click.echo(click.style("Using existing virtualenv...", bold=True), err=True)
# Remove the virtualenv.
cleanup_virtualenv(project, bare=True)
# Call this function again.
ensure_virtualenv(
project,
python=python,
site_packages=site_packages,
pypi_mirror=pypi_mirror,
)
def cleanup_virtualenv(project, bare=True):
"""Removes the virtualenv directory from the system."""
if not bare:
click.secho("Environment creation aborted.", fg="red")
try:
# Delete the virtualenv.
shutil.rmtree(project.virtualenv_location)
except OSError as e:
click.echo(
"{} An error occurred while removing {}!".format(
click.style("Error: ", fg="red", bold=True),
click.style(project.virtualenv_location, fg="green"),
),
err=True,
)
click.secho(e, fg="cyan", err=True)
def ensure_python(project, python=None):
# Runtime import is necessary due to the possibility that the environments module may have been reloaded.
if project.s.PIPENV_PYTHON and python is False:
python = project.s.PIPENV_PYTHON
def abort(msg=""):
click.echo(
"{}\nYou can specify specific versions of Python with:\n{}".format(
click.style(msg, fg="red"),
click.style(
"$ pipenv --python {}".format(os.sep.join(("path", "to", "python"))),
fg="yellow",
),
),
err=True,
)
sys.exit(1)
project.s.USING_DEFAULT_PYTHON = not python
# Find out which python is desired.
if not python:
python = project.required_python_version
if not python:
python = project.s.PIPENV_DEFAULT_PYTHON_VERSION
path_to_python = find_a_system_python(python)
if project.s.is_verbose():
click.echo(f"Using python: {python}", err=True)
click.echo(f"Path to python: {path_to_python}", err=True)
if not path_to_python and python is not None:
# We need to install Python.
click.echo(
"{}: Python {} {}".format(
click.style("Warning", fg="red", bold=True),
click.style(python, fg="cyan"),
"was not found on your system...",
),
err=True,
)
# check for python installers
from .installers import Asdf, InstallerError, InstallerNotFound, Pyenv
# prefer pyenv if both pyenv and asdf are installed as it's
# dedicated to python installs so probably the preferred
# method of the user for new python installs.
installer = None
if not project.s.PIPENV_DONT_USE_PYENV:
try:
installer = Pyenv(project)
except InstallerNotFound:
pass
if installer is None and not project.s.PIPENV_DONT_USE_ASDF:
try:
installer = Asdf(project)
except InstallerNotFound:
pass
if not installer:
abort("Neither 'pyenv' nor 'asdf' could be found to install Python.")
else:
if environments.SESSION_IS_INTERACTIVE or project.s.PIPENV_YES:
try:
version = installer.find_version_to_install(python)
except ValueError:
abort()
except InstallerError as e:
abort(f"Something went wrong while installing Python:\n{e.err}")
s = "{} {} {}".format(
"Would you like us to install",
click.style(f"CPython {version}", fg="green"),
f"with {installer}?",
)
# Prompt the user to continue...
if not (project.s.PIPENV_YES or click.confirm(s, default=True)):
abort()
else:
# Tell the user we're installing Python.
click.echo(
"{} {} {} {}{}".format(
click.style("Installing", bold=True),
click.style(f"CPython {version}", bold=True, fg="green"),
click.style(f"with {installer.cmd}", bold=True),
click.style("(this may take a few minutes)"),
click.style("...", bold=True),
)
)
with console.status(
"Installing python...", spinner=project.s.PIPENV_SPINNER
):
try:
c = installer.install(version)
except InstallerError as e:
err.print(
environments.PIPENV_SPINNER_FAIL_TEXT.format("Failed...")
)
click.echo("Something went wrong...", err=True)
click.secho(e.err, fg="cyan", err=True)
else:
console.print(
environments.PIPENV_SPINNER_OK_TEXT.format("Success!")
)
# Print the results, in a beautiful blue...
click.secho(c.stdout, fg="cyan", err=True)
# Clear the pythonfinder caches
from pipenv.vendor.pythonfinder import Finder
finder = Finder(system=False, global_search=True)
finder.find_python_version.cache_clear()
finder.find_all_python_versions.cache_clear()
# Find the newly installed Python, hopefully.
version = str(version)
path_to_python = find_a_system_python(version)
try:
assert python_version(path_to_python) == version
except AssertionError:
click.echo(
"{}: The Python you just installed is not available on your {}, apparently."
"".format(
click.style("Warning", fg="red", bold=True),
click.style("PATH", bold=True),
),
err=True,
)
sys.exit(1)
return path_to_python
def find_a_system_python(line):
"""Find a Python installation from a given line.
This tries to parse the line in various of ways:
* Looks like an absolute path? Use it directly.
* Looks like a py.exe call? Use py.exe to get the executable.
* Starts with "py" something? Looks like a python command. Try to find it
in PATH, and use it directly.
* Search for "python" and "pythonX.Y" executables in PATH to find a match.
* Nothing fits, return None.
"""
from pipenv.vendor.pythonfinder import Finder
finder = Finder(system=False, global_search=True)
if not line:
return next(iter(finder.find_all_python_versions()), None)
# Use the windows finder executable
if (line.startswith("py ") or line.startswith("py.exe ")) and os.name == "nt":
line = line.split(" ", 1)[1].lstrip("-")
python_entry = find_python(finder, line)
return python_entry
def do_where(project, virtualenv=False, bare=True):
"""Executes the where functionality."""
if not virtualenv:
if not project.pipfile_exists:
click.echo(
"No Pipfile present at project home. Consider running "
"{} first to automatically generate a Pipfile for you."
"".format(click.style("`pipenv install`", fg="green")),
err=True,
)
return
location = project.pipfile_location
# Shorten the virtual display of the path to the virtualenv.
if not bare:
location = shorten_path(location)
click.echo(
"Pipfile found at {}.\n Considering this to be the project home."
"".format(click.style(location, fg="green")),
err=True,
)
else:
click.echo(project.project_directory)
else:
location = project.virtualenv_location
if not bare:
click.secho(f"Virtualenv location: {location}", fg="green", err=True)
else:
click.echo(location)
def inline_activate_virtual_environment(project):
root = project.virtualenv_location
if os.path.exists(os.path.join(root, "pyvenv.cfg")):
_inline_activate_venv(project)
else:
_inline_activate_virtualenv(project)
if "VIRTUAL_ENV" not in os.environ:
os.environ["VIRTUAL_ENV"] = root
def _inline_activate_venv(project):
"""Built-in venv doesn't have activate_this.py, but doesn't need it anyway.
As long as we find the correct executable, built-in venv sets up the
environment automatically.
See: https://bugs.python.org/issue21496#msg218455
"""
components = []
for name in ("bin", "Scripts"):
bindir = os.path.join(project.virtualenv_location, name)
if os.path.exists(bindir):
components.append(bindir)
if "PATH" in os.environ:
components.append(os.environ["PATH"])
os.environ["PATH"] = os.pathsep.join(components)
def _inline_activate_virtualenv(project):
try:
activate_this = project._which("activate_this.py")
if not activate_this or not os.path.exists(activate_this):
raise exceptions.VirtualenvActivationException()
with open(activate_this) as f:
code = compile(f.read(), activate_this, "exec")
exec(code, dict(__file__=activate_this))
# Catch all errors, just in case.
except Exception:
click.echo(
"{}: There was an unexpected error while activating your "
"virtualenv. Continuing anyway...".format(
click.style("Warning", fg="red", bold=True)
),
err=True,
)
+2 -1
View File
@@ -6,6 +6,7 @@ import os
import shutil
import tempfile
import pipenv.utils.pip
from ._compat import tomllib
from .envbuild import BuildEnvironment
from .wrappers import Pep517HookCaller
@@ -60,7 +61,7 @@ def _do_build(hooks, env, dist, dest):
reqs = get_requires({})
log.info('Got build requires: %s', reqs)
env.pip_install(reqs)
pipenv.utils.pip.pip_install(reqs)
log.info('Installed dynamic build dependencies')
with tempfile.TemporaryDirectory() as td:
+3 -1
View File
@@ -7,6 +7,8 @@ import os
import shutil
import tempfile
import pipenv.utils.pip
try:
import importlib.metadata as imp_meta
except ImportError:
@@ -29,7 +31,7 @@ def _prep_meta(hooks, env, dest):
reqs = hooks.get_requires_for_build_wheel({})
log.info('Got build requires: %s', reqs)
env.pip_install(reqs)
pipenv.utils.pip.pip_install(reqs)
log.info('Installed dynamic build dependencies')
with tempfile.TemporaryDirectory() as td:
@@ -4,7 +4,7 @@ import tempfile
import pytest
from pipenv.core import import_requirements
from pipenv.utils.requirements import import_requirements
from pipenv.project import Project
+1 -1
View File
@@ -3,7 +3,7 @@ from tempfile import TemporaryDirectory
import pytest
from pipenv.core import warn_in_virtualenv
from pipenv.utils.virtualenv import warn_in_virtualenv
from pipenv.utils.environment import load_dot_env
from pipenv.utils.shell import temp_environ