comparison planemo/lib/python3.7/site-packages/pip/_internal/utils/outdated.py @ 1:56ad4e20f292 draft

"planemo upload commit 6eee67778febed82ddd413c3ca40b3183a3898f1"
author guerler
date Fri, 31 Jul 2020 00:32:28 -0400
parents
children
comparison
equal deleted inserted replaced
0:d30785e31577 1:56ad4e20f292
1 from __future__ import absolute_import
2
3 import datetime
4 import json
5 import logging
6 import os.path
7 import sys
8
9 from pip._vendor import lockfile, pkg_resources
10 from pip._vendor.packaging import version as packaging_version
11
12 from pip._internal.cli.cmdoptions import make_search_scope
13 from pip._internal.index import PackageFinder
14 from pip._internal.models.selection_prefs import SelectionPreferences
15 from pip._internal.utils.compat import WINDOWS
16 from pip._internal.utils.filesystem import check_path_owner
17 from pip._internal.utils.misc import ensure_dir, get_installed_version
18 from pip._internal.utils.packaging import get_installer
19 from pip._internal.utils.typing import MYPY_CHECK_RUNNING
20
21 if MYPY_CHECK_RUNNING:
22 import optparse
23 from typing import Any, Dict
24 from pip._internal.download import PipSession
25
26
27 SELFCHECK_DATE_FMT = "%Y-%m-%dT%H:%M:%SZ"
28
29
30 logger = logging.getLogger(__name__)
31
32
33 class SelfCheckState(object):
34 def __init__(self, cache_dir):
35 # type: (str) -> None
36 self.state = {} # type: Dict[str, Any]
37 self.statefile_path = None
38
39 # Try to load the existing state
40 if cache_dir:
41 self.statefile_path = os.path.join(cache_dir, "selfcheck.json")
42 try:
43 with open(self.statefile_path) as statefile:
44 self.state = json.load(statefile)[sys.prefix]
45 except (IOError, ValueError, KeyError):
46 # Explicitly suppressing exceptions, since we don't want to
47 # error out if the cache file is invalid.
48 pass
49
50 def save(self, pypi_version, current_time):
51 # type: (str, datetime.datetime) -> None
52 # If we do not have a path to cache in, don't bother saving.
53 if not self.statefile_path:
54 return
55
56 # Check to make sure that we own the directory
57 if not check_path_owner(os.path.dirname(self.statefile_path)):
58 return
59
60 # Now that we've ensured the directory is owned by this user, we'll go
61 # ahead and make sure that all our directories are created.
62 ensure_dir(os.path.dirname(self.statefile_path))
63
64 # Attempt to write out our version check file
65 with lockfile.LockFile(self.statefile_path):
66 if os.path.exists(self.statefile_path):
67 with open(self.statefile_path) as statefile:
68 state = json.load(statefile)
69 else:
70 state = {}
71
72 state[sys.prefix] = {
73 "last_check": current_time.strftime(SELFCHECK_DATE_FMT),
74 "pypi_version": pypi_version,
75 }
76
77 with open(self.statefile_path, "w") as statefile:
78 json.dump(state, statefile, sort_keys=True,
79 separators=(",", ":"))
80
81
82 def was_installed_by_pip(pkg):
83 # type: (str) -> bool
84 """Checks whether pkg was installed by pip
85
86 This is used not to display the upgrade message when pip is in fact
87 installed by system package manager, such as dnf on Fedora.
88 """
89 try:
90 dist = pkg_resources.get_distribution(pkg)
91 return "pip" == get_installer(dist)
92 except pkg_resources.DistributionNotFound:
93 return False
94
95
96 def pip_version_check(session, options):
97 # type: (PipSession, optparse.Values) -> None
98 """Check for an update for pip.
99
100 Limit the frequency of checks to once per week. State is stored either in
101 the active virtualenv or in the user's USER_CACHE_DIR keyed off the prefix
102 of the pip script path.
103 """
104 installed_version = get_installed_version("pip")
105 if not installed_version:
106 return
107
108 pip_version = packaging_version.parse(installed_version)
109 pypi_version = None
110
111 try:
112 state = SelfCheckState(cache_dir=options.cache_dir)
113
114 current_time = datetime.datetime.utcnow()
115 # Determine if we need to refresh the state
116 if "last_check" in state.state and "pypi_version" in state.state:
117 last_check = datetime.datetime.strptime(
118 state.state["last_check"],
119 SELFCHECK_DATE_FMT
120 )
121 if (current_time - last_check).total_seconds() < 7 * 24 * 60 * 60:
122 pypi_version = state.state["pypi_version"]
123
124 # Refresh the version if we need to or just see if we need to warn
125 if pypi_version is None:
126 # Lets use PackageFinder to see what the latest pip version is
127 search_scope = make_search_scope(options, suppress_no_index=True)
128
129 # Pass allow_yanked=False so we don't suggest upgrading to a
130 # yanked version.
131 selection_prefs = SelectionPreferences(
132 allow_yanked=False,
133 allow_all_prereleases=False, # Explicitly set to False
134 )
135
136 finder = PackageFinder.create(
137 search_scope=search_scope,
138 selection_prefs=selection_prefs,
139 trusted_hosts=options.trusted_hosts,
140 session=session,
141 )
142 candidate = finder.find_candidates("pip").get_best()
143 if candidate is None:
144 return
145 pypi_version = str(candidate.version)
146
147 # save that we've performed a check
148 state.save(pypi_version, current_time)
149
150 remote_version = packaging_version.parse(pypi_version)
151
152 local_version_is_older = (
153 pip_version < remote_version and
154 pip_version.base_version != remote_version.base_version and
155 was_installed_by_pip('pip')
156 )
157
158 # Determine if our pypi_version is older
159 if not local_version_is_older:
160 return
161
162 # Advise "python -m pip" on Windows to avoid issues
163 # with overwriting pip.exe.
164 if WINDOWS:
165 pip_cmd = "python -m pip"
166 else:
167 pip_cmd = "pip"
168 logger.warning(
169 "You are using pip version %s, however version %s is "
170 "available.\nYou should consider upgrading via the "
171 "'%s install --upgrade pip' command.",
172 pip_version, pypi_version, pip_cmd
173 )
174 except Exception:
175 logger.debug(
176 "There was an error checking the latest version of pip",
177 exc_info=True,
178 )