Skip to content

Commit

Permalink
Add --required-by option to list command
Browse files Browse the repository at this point in the history
This allows to do something like:

```
$ pip list --required-by mypackage
Package        Version
-------------- --------
asyncpg        0.23.0
httpx          0.18.1
Jinja2         2.11.3
minicli        0.5.0
openpyxl       3.0.7
progressist    0.1.0
PyJWT          2.1.0
roll           0.13.0
ujson          1.35
```

And yet more usesul in my workflow:

```
$ pip list --required-by mypackage --outdated
Package    Version Latest Type
---------- ------- ------ -----
Jinja2     2.11.3  3.0.1  wheel
ujson      1.35    4.0.2  wheel
```
  • Loading branch information
yohanboniface committed Jun 3, 2021
1 parent 3c1d181 commit 353fa51
Show file tree
Hide file tree
Showing 3 changed files with 38 additions and 0 deletions.
2 changes: 2 additions & 0 deletions news/10036.feature.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Add ``required-by`` option to the ``list`` command, in order to restrict the listed
packages to some package requirements (useful for eg. with ``--outdated``)
22 changes: 22 additions & 0 deletions src/pip/_internal/commands/list.py
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,13 @@ def add_options(self):
"installed packages.",
)

self.cmd_opts.add_option(
'--required-by',
action='store',
dest='required_by',
help="List packages that are dependencies the given package.",
)

self.cmd_opts.add_option(
'--exclude-editable',
action='store_false',
Expand Down Expand Up @@ -161,6 +168,9 @@ def run(self, options, args):
if options.not_required:
packages = self.get_not_required(packages, options)

if options.required_by:
packages = self.get_required_by(packages, options)

if options.outdated:
packages = self.get_outdated(packages, options)
elif options.uptodate:
Expand Down Expand Up @@ -194,6 +204,18 @@ def get_not_required(self, packages, options):
# get_uptodate
return list({pkg for pkg in packages if pkg.key not in dep_keys})

def get_required_by(self, packages, options):
# type: (List[Distribution], Values) -> List[Distribution]
dep_keys = set() # type: Set[Distribution]
for dist in packages:
if dist.project_name == options.required_by:
dep_keys = set(requirement.key for requirement in dist.requires())

# Create a set to remove duplicate packages, and cast it to a list
# to keep the return type consistent with get_outdated and
# get_uptodate
return list({pkg for pkg in packages if pkg.key in dep_keys})

def iter_packages_latest_infos(self, packages, options):
# type: (List[Distribution], Values) -> Iterator[Distribution]
with self._build_session(options) as session:
Expand Down
14 changes: 14 additions & 0 deletions tests/functional/test_list.py
Original file line number Diff line number Diff line change
Expand Up @@ -403,6 +403,20 @@ def test_outdated_not_required_flag(script, data):
assert [] == json.loads(result.stdout)


def test_required_by_flag(script, data):
"""
test the behavior of --required-by flag in the list command
"""
script.pip(
'install', '-f', data.find_links, '--no-index', 'require_simple==1.0'
)
result = script.pip(
'list', '-f', data.find_links, '--no-index',
'--required-by', 'require-simple', '--format=json',
)
assert [{'name': 'simple', 'version': '3.0'}] == json.loads(result.stdout)


def test_outdated_pre(script, data):
script.pip('install', '-f', data.find_links, '--no-index', 'simple==1.0')

Expand Down

0 comments on commit 353fa51

Please sign in to comment.