-
Notifications
You must be signed in to change notification settings - Fork 3k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
3 changed files
with
98 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
Add ``pip inspect`` command to obtain the list of installed distributions and other | ||
information about the Python environment, in JSON format. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,91 @@ | ||
import json | ||
import sys | ||
from optparse import Values | ||
from typing import Any, Dict, List | ||
|
||
from pip._vendor.packaging.markers import default_environment | ||
|
||
from pip import __version__ | ||
from pip._internal.cli import cmdoptions | ||
from pip._internal.cli.req_command import Command | ||
from pip._internal.cli.status_codes import SUCCESS | ||
from pip._internal.metadata import BaseDistribution, get_environment | ||
from pip._internal.utils.compat import stdlib_pkgs | ||
from pip._internal.utils.urls import path_to_url | ||
|
||
|
||
class InspectCommand(Command): | ||
""" | ||
Inspect the content of a Python environment. | ||
""" | ||
|
||
ignore_require_venv = True | ||
usage = """ | ||
%prog [options]""" | ||
|
||
def add_options(self) -> None: | ||
self.cmd_opts.add_option( | ||
"-l", | ||
"--local", | ||
action="store_true", | ||
default=False, | ||
help=( | ||
"If in a virtualenv that has global access, do not list " | ||
"globally-installed packages." | ||
), | ||
) | ||
self.cmd_opts.add_option( | ||
"--user", | ||
dest="user", | ||
action="store_true", | ||
default=False, | ||
help="Only output packages installed in user-site.", | ||
) | ||
self.cmd_opts.add_option(cmdoptions.list_path()) | ||
self.parser.insert_option_group(0, self.cmd_opts) | ||
|
||
def run(self, options: Values, args: List[str]) -> int: | ||
cmdoptions.check_list_path_option(options) | ||
dists = get_environment(options.path).iter_installed_distributions( | ||
local_only=options.local, | ||
user_only=options.user, | ||
skip=set(stdlib_pkgs), | ||
) | ||
output = { | ||
"version": "0", | ||
"pip_version": __version__, | ||
"installed": [self._dist_to_dict(dist) for dist in dists], | ||
"environment": default_environment(), | ||
} | ||
json.dump(output, sys.stdout, indent=2, ensure_ascii=True) | ||
return SUCCESS | ||
|
||
def _dist_to_dict(self, dist: BaseDistribution) -> Dict[str, Any]: | ||
res: Dict[str, Any] = { | ||
"metadata": dist.metadata_dict, | ||
"location": dist.location, # TODO is this the best location to report ? | ||
} | ||
# direct_url | ||
direct_url = dist.direct_url | ||
if direct_url is not None: | ||
res["direct_url"] = direct_url.to_dict() | ||
else: | ||
# Handle legacy editable installs. | ||
editable_project_location = dist.editable_project_location | ||
if editable_project_location is not None: | ||
res["direct_url"] = { | ||
"url": path_to_url(editable_project_location), | ||
"dir_info": { | ||
"editable": True, | ||
}, | ||
} | ||
# is_direct is redundant but present for symmetry with the installation report. | ||
res["is_direct"] = "direct_url" in res | ||
# installer | ||
installer = dist.installer | ||
if dist.installer: | ||
res["installer"] = installer | ||
# requested | ||
if dist.installed_with_dist_info: | ||
res["requested"] = dist.requested | ||
return res |