Skip to content

Commit 77a3e70

Browse files
author
Noah Gorny
committed
search: Use json API in list-all-versions instead of xmlrpc API
1 parent 26e6a47 commit 77a3e70

File tree

1 file changed

+33
-12
lines changed

1 file changed

+33
-12
lines changed

src/pip/_internal/commands/search.py

Lines changed: 33 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import json
12
import logging
23
import shutil
34
import sys
@@ -7,15 +8,18 @@
78
from optparse import Values
89
from typing import TYPE_CHECKING, Dict, Iterable, List, Optional
910

11+
from pip._vendor import requests
1012
from pip._vendor.packaging.utils import canonicalize_name
1113
from pip._vendor.packaging.version import parse as parse_version
14+
from pip._vendor.six.moves.urllib import parse as urllib_parse
1215

1316
from pip._internal.cli.base_command import Command
1417
from pip._internal.cli.req_command import SessionCommandMixin
1518
from pip._internal.cli.status_codes import NO_MATCHES_FOUND, SUCCESS
16-
from pip._internal.exceptions import CommandError
19+
from pip._internal.exceptions import CommandError, NetworkConnectionError
1720
from pip._internal.metadata import get_default_environment
1821
from pip._internal.models.index import PyPI
22+
from pip._internal.network.utils import raise_for_status
1923
from pip._internal.network.xmlrpc import PipXmlrpcTransport
2024
from pip._internal.utils.logging import indent_log
2125
from pip._internal.utils.misc import write_output
@@ -58,22 +62,31 @@ def add_options(self):
5862

5963
def get_all_package_versions(self, query, options):
6064
# type: (List[str], Values) -> List[Dict[str, str]]
61-
pypi = self.get_pypi(options)
62-
6365
canonized_query = [canonicalize_name(q) for q in query]
6466

65-
result_hits = []
67+
result_hits = [] # type: List[Dict[str, str]]
6668
for q in canonized_query:
67-
versions = pypi.package_releases(q, True)
68-
if not versions:
69-
continue
70-
71-
latest = highest_version(versions)
72-
hit = pypi.release_data(q, latest)
69+
try:
70+
package_data = self.get_pypi_json(options, q)
71+
except (requests.ConnectionError,
72+
requests.Timeout,
73+
NetworkConnectionError) as exc:
74+
exc = str(exc)
75+
if '404' in exc:
76+
err = 'Got 404 error, make sure the package name is valid.'
77+
else:
78+
err = exc
79+
logger.error(
80+
'Failed to fetch data of package "%s": %s', q, err)
81+
return result_hits
82+
83+
versions = package_data.get('releases', {}) # type: Dict[str, str]
84+
85+
info = package_data.get('info', {}) # type: Dict[str, str]
7386
for version in versions:
7487
result_hits.append(
75-
{'name': hit['name'],
76-
'summary': hit['summary'],
88+
{'name': info.get('name', ''),
89+
'summary': info.get('summary', ''),
7790
'version': version}
7891
)
7992
return result_hits
@@ -109,6 +122,14 @@ def get_pypi(self, options):
109122
transport = PipXmlrpcTransport(index_url, session)
110123
return xmlrpc.client.ServerProxy(index_url, transport)
111124

125+
def get_pypi_json(self, options, query):
126+
# type: (Values, str) -> Dict[str, Dict[str, str]]
127+
resp = requests.get(
128+
urllib_parse.urljoin(
129+
options.index, '{}/{}/{}'.format('pypi', query, 'json')))
130+
raise_for_status(resp)
131+
return json.loads(resp.content.decode('utf-8'))
132+
112133
def search(self, query, options):
113134
# type: (List[str], Values) -> List[Dict[str, str]]
114135
pypi = self.get_pypi(options)

0 commit comments

Comments
 (0)