22

I have a file that I suspect was installed by pip. How can I find which package installed that file?

In other words, I'm looking for a command similar to pacman -Qo filename or dpkg -S filename, but for pip. Does it exist? Or should I use some combination of pip and grep? In that case, I don't know how to list all the file installed.

DdD
  • 572
  • 1
  • 5
  • 12
  • 1
    What do you mean with “file”? A module? A package? – poke Nov 02 '15 at 17:53
  • @poke In my hd I have a file .py and I want to know if I installed a package years ago that copied that file into my computer. (actually the file is `/usr/bin/rst2html.py`) but my question is how to do it in general. – DdD Nov 02 '15 at 18:03
  • Related: [Which python package owns a binary?](https://stackoverflow.com/q/55864568/5353461) – Tom Hale Apr 27 '19 at 08:10
  • Does this answer your question? [Python3 (pip): find which package provides a particular module](https://stackoverflow.com/questions/63847850/python3-pip-find-which-package-provides-a-particular-module) – sinoroc Apr 26 '23 at 21:27

4 Answers4

13

You could try with

pip list | tail -n +3 | cut -d" " -f1 | xargs pip show -f | grep "filename"

Then search through the results looking for that file.

zhigang
  • 6,597
  • 4
  • 30
  • 24
JRD
  • 1,957
  • 1
  • 12
  • 17
  • Thanks, it almost works. But, for most of the packages I get `Files: Cannot locate installed-files.txt` is it an issue of my system? – DdD Nov 02 '15 at 18:19
  • 1
    @KraZmAzzD: I think `pip list` includes packages that weren't installed by `pip` itself, but by your system package manager. These will usually not include the `installed-files.txt` file. – Rörd Nov 02 '15 at 18:21
  • @Rörd grep may work, but it would need context (several lines up) to get the actual package name not just the file name. – JRD Nov 02 '15 at 18:23
  • 1
    For users of future `pip` versions: `s/pip list/pip list --format=legacy/` if you get an error `no such option: ----------------`. – hoefling Jan 19 '18 at 13:46
  • Replace `grep "filename"` with `grep -B10 "filename"` to show some more metadata from the package in question (which or may or may not reflect the directory used in the `Files` section. – Per Lundberg Aug 22 '23 at 09:41
3

Since Python 3.8 standard library offers a more straightforward approach than Nathaniel 's:

import pathlib
import sys

if sys.version_info >= (3, 8):
    from importlib import metadata as importlib_metadata
else:
    import importlib_metadata


path_query_pattern = sys.argv[1]
for dist in importlib_metadata.distributions():
    paths = dist.files

    for file in dist.files:
        if pathlib.Path(file).match(path_query_pattern):
            print(dist.metadata["Name"] + ' --- "' + str(file) + '"')

The backport of the importlib_metadata for older python versions is available via pip.
Based on this answer.

Usage:

>>> python lookup_file.py pip.exe
pip --- "..\..\Scripts\pip.exe"

>>> python lookup_file.py Scripts\pip.exe
pip --- "..\..\Scripts\pip.exe"
Igor
  • 1,359
  • 19
  • 34
2

You can use a python script like this:

#!/usr/bin/env python

import sys
try:
    from pip.utils import get_installed_distributions
except ModuleNotFoundError:
    from pip._internal.utils.misc import get_installed_distributions

MYPATH=sys.argv[1]
for dist in get_installed_distributions():
    # RECORDs should be part of .dist-info metadatas
    if dist.has_metadata('RECORD'):
        lines = dist.get_metadata_lines('RECORD')
        paths = [l.split(',')[0] for l in lines]
    # Otherwise use pip's log for .egg-info's
    elif dist.has_metadata('installed-files.txt'):
        paths = dist.get_metadata_lines('installed-files.txt')
    else:
        paths = []

    if MYPATH in paths:
        print(dist.project_name)

Usage looks like this:

$ python lookup_file.py requests/__init__.py 
requests

I wrote a more complete version here, with absolute paths:

https://github.com/nbeaver/pip_file_lookup

1

Try this!

find_pkg_by_filename(){ for pkg in $(pip list | cut -d" " -f1) ; do if pip show -f "$pkg" | grep "$1" ; then echo "=== Above files found in package $pkg ===" ; fi ; done ; }

find_pkg_by_filename somefilename

Note that if you add -q to the grep, it will exit as soon as there's a match, and then pip will complain about broken pipes.

Chris Cogdon
  • 7,481
  • 5
  • 38
  • 30