Skip to content

Once a day check PyPI for the latest version of pip #1214

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 6 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion pip/basecommand.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
from pip.baseparser import ConfigOptionParser, UpdatingDefaultsHelpFormatter
from pip.status_codes import (SUCCESS, ERROR, UNKNOWN_ERROR, VIRTUALENV_NOT_FOUND,
PREVIOUS_BUILD_DIR_ERROR)
from pip.util import get_prog
from pip.util import get_prog, latest_version_check


__all__ = ['Command']
Expand Down Expand Up @@ -115,6 +115,10 @@ def main(self, args):
else:
log_fp = None

# Check if we're using the latest version of pip available
if not options.disable_version_check:
latest_version_check(session=self._build_session(options))

exit = SUCCESS
store_log = False
try:
Expand Down
8 changes: 8 additions & 0 deletions pip/cmdoptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -304,6 +304,13 @@ def make(self):
default=False,
help="Don't clean up build directories.")

disable_version_check = OptionMaker(
"--disable-version-check",
dest="disable_version_check",
action="store_true",
default=False,
help="Don't check PyPI for new versions of pip.")


##########
# groups #
Expand All @@ -327,6 +334,7 @@ def make(self):
skip_requirements_regex,
exists_action,
cert,
disable_version_check,
]
}

Expand Down
64 changes: 64 additions & 0 deletions pip/util.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import datetime
import json
import sys
import shutil
import os
Expand Down Expand Up @@ -717,3 +719,65 @@ def is_prerelease(vers):

parsed = version._normalized_key(normalized)
return any([any([y in set(["a", "b", "c", "rc", "dev"]) for y in x]) for x in parsed])


def latest_version_check(session, frequency=7 * 24 * 60 * 60):
"""
Attempt to determine if we're using the latest version of pip or not. Keeps
a small state file stored in ~/.pip/ to store when the last time we checked
was and what the version was.
"""
pypi_version = None

try:
import pip # imported here to prevent circular imports

current_time = datetime.datetime.utcnow()

fmt = "%Y-%m-%dT%H:%M:%S"
statefile_path = os.path.expanduser("~/.pip/versioncheck")

# Load the existing state
try:
with open(statefile_path) as statefile:
state = json.load(statefile)
except (IOError, ValueError):
state = {}

# Determine if we need to refresh the state
if "last-check" in state and "version" in state:
last_check = datetime.datetime.strptime(state["last-check"], fmt)
if (current_time - last_check).total_seconds() < frequency:
pypi_version = state["version"]

# Refresh the version if we need to
if pypi_version is None:
resp = session.get("https://pypi.python.org/pypi/pip/json",
headers={"Accept": "application/json"},
)
resp.raise_for_status()
pypi_version = resp.json()["info"]["version"]

# Determine if our pypi_version is older
need_update = (pkg_resources.parse_version(pip.__version__)
< pkg_resources.parse_version(pypi_version))
if need_update:
logger.warn(
"You are using pip version %s, however version %s is "
"available. You should consider upgrading via the pip install "
"--upgrade pip command." % (pip.__version__, pypi_version))

# Attempt to write out our version check file
with open(statefile_path, "w") as statefile:
json.dump(
{
"last-check": current_time.strftime(fmt),
"pypi_version": pypi_version,
},
statefile,
)
except Exception:
logger.debug(
"There was an error checking the latest version of pip",
exc_info=True,
)
6 changes: 6 additions & 0 deletions tests/unit/test_basecommand.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,15 @@
class FakeCommand(Command):
name = 'fake'
summary = name

def __init__(self, error=False):
self.error = error
super(FakeCommand, self).__init__()

def main(self, args):
args.append("--disable-version-check")
return super(FakeCommand, self).main(args)

def run(self, options, args):
logger.info("fake")
if self.error:
Expand Down