On Tue, 27 Apr 2021 at 18:01, Brett Cannon <br...@python.org> wrote: > Unfortunately I thought importlib.metadata would have used the module name > instead of the metadata details, but in hindsight am guessing that the > .dist-info is what it's using to do the lookup and that's based on the > package name instead of the project name. > > This is a long-standing issue with projects that use project names which > differ from their module name, but there's no good way without checking what > files a project installed (which is what you're doing below).
That's correct. There is no link from a given import name back to the PyPI project name. And the metadata for installed packages (defined here: https://packaging.python.org/specifications/recording-installed-packages/) is keyed on the PyPI project name, as the OP noted ("beautifulsoup4" rather than "bs4", "setuptools" rather than "pkg_resources", etc). >> This is the best I could come up with from reading the docs: >> >> import bs4 #<- This is the module we want the version of >> >> import importlib >> import sys >> from itertools import chain >> from pathlib import Path >> >> loaders = sys.meta_path >> >> target_path = Path(bs4.__file__) >> >> distros = list(chain(*(finder.find_distributions() for finder in loaders >> if hasattr(finder, 'find_distributions')))) >> distros_files = chain(*(f for f in (d.files for d in distros))) >> distro_files = [(d, d.locate_file(f)) for d in distros if d.files for f >> in d.files] >> matching = [d for d, f in distro_files if f == target_path] >> >> for match in matching: >> print("Found Version:", match.version) The following is a bit simpler. The file.locate() method of a distribution is undocumented - but I tried to use resolve() on the path object I got from dist.files, and it appears not to be implemented (at least in Python 3.9) - PackagePath objects are a subclass of *Pure* Path objects, not concrete paths :-( TBH, I suspect the fact that it's undocumented is an oversight, it's clearly deliberately added. import importlib.metadata from pathlib import Path import pkg_resources target = Path(pkg_resources.__file__) for dist in importlib.metadata.distributions(): for file in dist.files: path = file.locate() if path == target: print(f"{dist.metadata['name']}: {dist.version}") break To be honest, if anyone were interested in making a PEP from any of this, having Python modules contain a __distribution_name__ attribute that links the module back to the PyPI distribution, would probably be more useful than standardising __version__. But I'm not sufficiently interested to do anything more than mention that as a possibility. Paul _______________________________________________ Python-Dev mailing list -- python-dev@python.org To unsubscribe send an email to python-dev-le...@python.org https://mail.python.org/mailman3/lists/python-dev.python.org/ Message archived at https://mail.python.org/archives/list/python-dev@python.org/message/66G7A5ZZRYT7H6MRJVELFMC23IDP67CL/ Code of Conduct: http://python.org/psf/codeofconduct/