Skip to content

Commit

Permalink
Remove pkg_resources usages from 'pip show'
Browse files Browse the repository at this point in the history
  • Loading branch information
uranusjr committed Jul 13, 2021
1 parent 3b8c83d commit f3c5344
Show file tree
Hide file tree
Showing 2 changed files with 59 additions and 68 deletions.
125 changes: 57 additions & 68 deletions src/pip/_internal/commands/show.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
import csv
import logging
import os
from email.parser import FeedParser
from optparse import Values
from typing import Dict, Iterator, List
from typing import Dict, Iterator, List, Optional

from pip._vendor import pkg_resources
from pip._vendor.packaging.utils import canonicalize_name

from pip._internal.cli.base_command import Command
from pip._internal.cli.status_codes import ERROR, SUCCESS
from pip._internal.metadata import BaseDistribution, get_default_environment
from pip._internal.utils.misc import write_output

logger = logging.getLogger(__name__)
Expand Down Expand Up @@ -58,85 +58,74 @@ def search_packages_info(query):
pip generated 'installed-files.txt' in the distributions '.egg-info'
directory.
"""
installed = {}
for p in pkg_resources.working_set:
installed[canonicalize_name(p.project_name)] = p
env = get_default_environment()

installed = {
dist.canonical_name: dist
for dist in env.iter_distributions()
}
query_names = [canonicalize_name(name) for name in query]
missing = sorted(
[name for name, pkg in zip(query, query_names) if pkg not in installed]
)
if missing:
logger.warning('Package(s) not found: %s', ', '.join(missing))

def get_requiring_packages(package_name):
def get_requiring_packages(canonical_name):
# type: (str) -> List[str]
canonical_name = canonicalize_name(package_name)
return [
pkg.project_name for pkg in pkg_resources.working_set
if canonical_name in
[canonicalize_name(required.name) for required in
pkg.requires()]
dist.canonical_name
for dist in env.iter_distributions()
if canonical_name in {
canonicalize_name(d.name) for d in dist.iter_dependencies()
}
]

for dist in [installed[pkg] for pkg in query_names if pkg in installed]:
def _files_from_record(dist: BaseDistribution) -> Optional[Iterator[str]]:
try:
text = dist.read_text('RECORD')
except FileNotFoundError:
return None
return (row[0] for row in csv.reader(text.splitlines()))

def _files_from_installed_files(dist: BaseDistribution) -> Optional[Iterator[str]]:
try:
text = dist.read_text('installed-files.txt')
except FileNotFoundError:
return None
return (p for p in text.splitlines(keepends=False) if p)

for query_name in query_names:
try:
dist = installed[query_name]
except KeyError:
continue
package = {
'name': dist.project_name,
'version': dist.version,
'location': dist.location,
'requires': [dep.project_name for dep in dist.requires()],
'required_by': get_requiring_packages(dist.project_name)
'name': dist.canonical_name,
'version': str(dist.version),
'location': dist.location or "",
'requires': [req.name for req in dist.iter_dependencies()],
'required_by': get_requiring_packages(dist.canonical_name),
'installer': dist.installer,
'metadata-version': dist.metadata_version,
'classifiers': dist.metadata.get_all('Classifiers'),
}
file_list = None
metadata = ''
if isinstance(dist, pkg_resources.DistInfoDistribution):
# RECORDs should be part of .dist-info metadatas
if dist.has_metadata('RECORD'):
lines = dist.get_metadata_lines('RECORD')
paths = [line.split(',')[0] for line in lines]
paths = [os.path.join(dist.location, p) for p in paths]
file_list = [os.path.relpath(p, dist.location) for p in paths]

if dist.has_metadata('METADATA'):
metadata = dist.get_metadata('METADATA')
else:
# Otherwise use pip's log for .egg-info's
if dist.has_metadata('installed-files.txt'):
paths = dist.get_metadata_lines('installed-files.txt')
paths = [os.path.join(dist.egg_info, p) for p in paths]
file_list = [os.path.relpath(p, dist.location) for p in paths]

if dist.has_metadata('PKG-INFO'):
metadata = dist.get_metadata('PKG-INFO')

if dist.has_metadata('entry_points.txt'):
entry_points = dist.get_metadata_lines('entry_points.txt')
package['entry_points'] = entry_points

if dist.has_metadata('INSTALLER'):
for line in dist.get_metadata_lines('INSTALLER'):
if line.strip():
package['installer'] = line.strip()
break

# @todo: Should pkg_resources.Distribution have a
# `get_pkg_info` method?
feed_parser = FeedParser()
feed_parser.feed(metadata)
pkg_info_dict = feed_parser.close()
for key in ('metadata-version', 'summary',
'home-page', 'author', 'author-email', 'license'):
package[key] = pkg_info_dict.get(key)

# It looks like FeedParser cannot deal with repeated headers
classifiers = []
for line in metadata.splitlines():
if line.startswith('Classifier: '):
classifiers.append(line[len('Classifier: '):])
package['classifiers'] = classifiers

if file_list:
package['files'] = sorted(file_list)

for key in ('Summary', 'Home-page', 'Author', 'Author-email', 'License'):
package[key] = dist.metadata[key]

try:
entry_points_text = dist.read_text('entry_points.txt')
package['entry_points'] = entry_points_text.splitlines(keepends=False)
except FileNotFoundError:
pass
if dist.installer:
package['installer'] = dist.installer

files = _files_from_record(dist) or _files_from_installed_files(dist)
if files:
package['files'] = sorted(os.path.relpath(p, dist.location) for p in files)

yield package


Expand Down
2 changes: 2 additions & 0 deletions src/pip/_internal/metadata/pkg_resources.py
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,8 @@ def in_usersite(self) -> bool:
return misc.dist_in_usersite(self._dist)

def read_text(self, name: str) -> str:
if not self._dist.has_metadata(name):
raise FileNotFoundError(name)
return self._dist.get_metadata(name)

def iter_entry_points(self) -> Iterable[BaseEntryPoint]:
Expand Down

0 comments on commit f3c5344

Please sign in to comment.