1

Say we are importing some 3rd party package or module called xyz (that's not "built-in" like datetime) with import xyz. xyz's PyPI name is usually the same, so would appear as xyz in pip list. However, as far as I know, there isn't a rule that says this has to be case; for example, google-pasta has its module named pasta.

Given the name of module or package I'm importing, is there a way to determine which PyPI package it came from (besides guessing the PyPI package and looking at the source code)? And conversely, is there a way to tell which packages and modules a given PyPI installation is introducing to the namespace?

flow2k
  • 3,999
  • 40
  • 55
  • 1
    "Given the name of module or package I'm importing" Do you also assume the package is actually installed? Or do you also need to cover, say, finding/inheriting some code and having to figure out which packages to install to get it to work? Note that actual package names are not necessarily unique, e.g. the ``PIL`` import is provided both by the ``PIL`` and ``Pillow`` pypi packages. – MisterMiyagi Apr 05 '20 at 09:07
  • @MisterMiyagi, yes, please assume the package is installed. Originally, what got me thinking about this is: *I'm having an issue with this module I'm importing; maybe upgrading will fix it? But to do that, I need to find the PyPI name to give to pip...* – flow2k Apr 05 '20 at 09:16
  • https://stackoverflow.com/a/60975978/11138259 – sinoroc Apr 05 '20 at 10:19

1 Answers1

1

I believe something like the following should work:

#!/usr/bin/env python3

import importlib.util
import pathlib

import importlib_metadata

def get_distribution(file_name):
    result = None
    for distribution in importlib_metadata.distributions():
        try:
            relative = (
                pathlib.Path(file_name)
                .relative_to(distribution.locate_file(''))
            )
        except ValueError:
            pass
        else:
            if relative in distribution.files:
                result = distribution
    return result

def alpha():
    file_name = importlib.util.find_spec('easy_install').origin
    distribution = get_distribution(file_name)
    print("alpha", distribution.metadata['Name'])

def bravo():
    file_name = importlib_metadata.__file__
    distribution = get_distribution(file_name)
    print("bravo", distribution.metadata['Name'])

if __name__ == '__main__':
    alpha()
    bravo()
sinoroc
  • 18,409
  • 2
  • 39
  • 70