Skip to content

Commit

Permalink
suppress pip version warning and auto-update shared libraries (#318)
Browse files Browse the repository at this point in the history
  • Loading branch information
Chad Smith authored Jan 7, 2020
1 parent 72bd386 commit 7f2a54d
Show file tree
Hide file tree
Showing 8 changed files with 62 additions and 16 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ See Contributing for how to update this file.
<a href="https://travis-ci.org/pipxproject/pipx"><img src="https://travis-ci.org/pipxproject/pipx.svg?branch=master" /></a>

<a href="https://pypi.python.org/pypi/pipx/">
<img src="https://img.shields.io/badge/pypi-0.15.0.1-blue.svg" /></a>
<img src="https://img.shields.io/badge/pypi-0.15.1.0-blue.svg" /></a>
<a href="https://github.com/ambv/black"><img alt="Code style: black" src="https://img.shields.io/badge/code%20style-black-000000.svg"></a>
</p>

Expand Down
6 changes: 4 additions & 2 deletions docs/changelog.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
0.15.0.1
0.15.1.0

- [bugfix] pass pip arguments to pip when determining package name
- Add Python 3.8 to PyPI classifier and travis test matrix
- [feature] auto-upgrade shared libraries, including pip, if older than one month. Hide all pip warnings that a new version is available. (#264)
- [bugfix] pass pip arguments to pip when determining package name (#320)

0.15.0.0

Expand Down
2 changes: 1 addition & 1 deletion docs/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ See Contributing for how to update this file.
<a href="https://travis-ci.org/pipxproject/pipx"><img src="https://travis-ci.org/pipxproject/pipx.svg?branch=master" /></a>

<a href="https://pypi.python.org/pypi/pipx/">
<img src="https://img.shields.io/badge/pypi-0.15.0.1-blue.svg" /></a>
<img src="https://img.shields.io/badge/pypi-0.15.1.0-blue.svg" /></a>
<a href="https://github.com/ambv/black"><img alt="Code style: black" src="https://img.shields.io/badge/code%20style-black-000000.svg"></a>
</p>

Expand Down
2 changes: 1 addition & 1 deletion src/pipx/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
from .util import PipxError, mkdir
from .venv import VenvContainer

__version__ = "0.15.0.1"
__version__ = "0.15.1.0"


def simple_parse_version(s, segments=4) -> Tuple[Union[int, str], ...]:
Expand Down
26 changes: 23 additions & 3 deletions src/pipx/shared_libs.py
Original file line number Diff line number Diff line change
@@ -1,16 +1,21 @@
import logging
from pathlib import Path
from typing import List
import time
import datetime

from pipx.animate import animate
from pipx.constants import DEFAULT_PYTHON, PIPX_SHARED_LIBS, WINDOWS
from pipx.util import get_site_packages, get_venv_paths, run

SHARED_LIBS_MAX_AGE_SEC = datetime.timedelta(days=30).total_seconds()


class _SharedLibs:
def __init__(self):
self.root = PIPX_SHARED_LIBS
self.bin_path, self.python_path = get_venv_paths(self.root)
self.pip_path = self.bin_path / ("pip" if not WINDOWS else "pip.exe")
# i.e. bin_path is ~/.local/pipx/shared/bin
# i.e. python_path is ~/.local/pipx/shared/python
self._site_packages = None
Expand All @@ -31,10 +36,23 @@ def create(self, pip_args: List[str], verbose: bool = False):

@property
def is_valid(self):
return (
self.python_path.is_file()
and (self.bin_path / ("pip" if not WINDOWS else "pip.exe")).is_file()
return self.python_path.is_file() and self.pip_path.is_file()

@property
def needs_upgrade(self):
if self.has_been_updated_this_run:
return False

if not self.pip_path.is_file():
return True

now = time.time()
time_since_last_update_sec = now - self.pip_path.stat().st_mtime
logging.info(
f"Time since last upgrade of shared libs, in seconds: {time_since_last_update_sec}. "
f"Upgrade will be run by pipx if greater than {SHARED_LIBS_MAX_AGE_SEC}."
)
return time_since_last_update_sec > SHARED_LIBS_MAX_AGE_SEC

def upgrade(self, pip_args: List[str], verbose: bool = False):
# Don't try to upgrade multiple times per run
Expand Down Expand Up @@ -64,6 +82,8 @@ def upgrade(self, pip_args: List[str], verbose: bool = False):
]
)
self.has_been_updated_this_run = True
self.pip_path.touch()

except Exception:
logging.error("Failed to upgrade shared libraries", exc_info=True)

Expand Down
1 change: 1 addition & 0 deletions src/pipx/util.py
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,7 @@ def run_subprocess(
# pipx directories to it, and can make it appear to venvs as though
# pipx dependencies are in the venv path (#233)
env = {k: v for k, v in os.environ.items() if k.upper() != "PYTHONPATH"}
env["PIP_DISABLE_PIP_VERSION_CHECK"] = "1"
cmd_str = " ".join(str(c) for c in cmd)
logging.info(f"running {cmd_str}")
# windows cannot take Path objects, only strings
Expand Down
15 changes: 7 additions & 8 deletions src/pipx/venv.py
Original file line number Diff line number Diff line change
Expand Up @@ -88,17 +88,16 @@ def __init__(
except StopIteration:
self._existing = False

if self._existing and self.uses_shared_libs and not shared_libs.is_valid:
logging.warning(
f"Shared libraries not found, but are required for package {self.root.name}. "
"Attempting to install now."
)
shared_libs.create([])
if self._existing and self.uses_shared_libs:
if shared_libs.is_valid:
logging.info("Successfully created shared libraries")
if shared_libs.needs_upgrade:
shared_libs.upgrade([], verbose)
else:
shared_libs.create([], verbose)

if not shared_libs.is_valid:
raise PipxError(
f"Error: pipx's shared venv is invalid and "
f"Error: pipx's shared venv {shared_libs.root} is invalid and "
"needs re-installation. To fix this, install or reinstall a "
"package. For example,\n"
f" pipx install {self.root.name} --force"
Expand Down
24 changes: 24 additions & 0 deletions tests/test_shared_libs.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import os
import time
import pytest # type: ignore
from pipx import shared_libs


now = time.time()


@pytest.mark.parametrize(
"mtime,needs_upgrade",
[
(now - shared_libs.SHARED_LIBS_MAX_AGE_SEC - 600, True),
(now - shared_libs.SHARED_LIBS_MAX_AGE_SEC + 600, False),
],
)
def test_auto_update_shared_libs(capsys, pipx_temp_env, mtime, needs_upgrade):
shared_libs.shared_libs.create([], verbose=True)
shared_libs.shared_libs.has_been_updated_this_run = False

access_time = now # this can be anything
os.utime(shared_libs.shared_libs.pip_path, (access_time, mtime))

assert shared_libs.shared_libs.needs_upgrade is needs_upgrade

0 comments on commit 7f2a54d

Please sign in to comment.