You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Originally written up at the typeshed repo: python/typeshed#7513. The conclusion was that this is a bug in the implementation rather than an incorrect annotation.
To my surprise, I discovered in matrix-org/synapse#12223 that it is possible for importlib.metadata.version(...) to return None. To reproduce this:
Create a new virtual environment. I'm using CPython 3.10.2 as my interpreter.
Within the venv, pip install bottle. (Any package will do; I choose bottle because it's small and doesn't have any dependencies).
No-one in their right mind should do step 4 willingly, but I have seen it happen in the wild (matrix-org/synapse#12223). We suspected a botched backup or similar was to blame.
I'm not familiar with all the machinery of Python package management, but I think I'd expect there to be a PackageNotFoundError raised in this situation? (I can imagine a package that doesn't declare its version, where version() returning None might make sense; but that feels odd.) Is the behaviour as intended?
Yes, the issues are related, where .version and .name returning None are specific manifestations of the metadata not having that key and the behavior being ill-defined.
I haven't yet decided if metadata items being undefined should result in None or raise an Exception (maybe KeyError).
For the specific case of a missing Name or Version, however, the packaging spec says that these fields are required (https://packaging.python.org/en/latest/specifications/core-metadata/#core-metadata-specifications), so it may be reasonable for the behavior when the specification is not met that the resulting behavior would be undefined (i.e. importlib.metadata should be able to assume the specification). It's outside the scope of importlib.metadata to detect, report, and repair invalid metadata. I would welcome and even encourage a third-party package to take on the responsibility of validating all distributions in an environment and reporting on non-compliant aspects.
In that sense, the type declaration is correct. .name and .version should always return str or raise an exception.
This additional example leads me stronger toward the position that .metadata[missing] should raise a KeyError, which would also fix this issue.
I'd also argue that if the metadata file is missing altogether, that should perhaps be a different error. That is, missing metadata is different from null metadata. Right now, the two are indistinguishable from the interface.
I'd expect there to be a PackageNotFoundError raised in this situation
That doesn't sound quite right to me. If there's a .dist-info directory, that implies a package is present. e.g.:
~ $ mkdir foo.dist-info
~ $ py -c "import importlib.metadata as md; print(md.distribution('foo'))"
<importlib.metadata.PathDistribution object at 0x1032f8580>
I'm going to ponder this one some more and probably address the .metadata issue(s) first before making any pronouncements on the best approach here.
Activity
DMRobertson commentedon Mar 18, 2022
Originally written up at the typeshed repo: python/typeshed#7513. The conclusion was that this is a bug in the implementation rather than an incorrect annotation.
To my surprise, I discovered in matrix-org/synapse#12223 that it is possible for
importlib.metadata.version(...)to returnNone. To reproduce this:pip install bottle. (Any package will do; I choosebottlebecause it's small and doesn't have any dependencies).versionofbottle:pip show bottleto find thesite-packageslocationbottle-VERSION-.dist-infodirectory: `rm /path/to/site-packages/bottle-VERSION.dist-info/*'.versionofbottleis now judged to beNone:pip show bottlenow determines thatbottleisn't installed:As well as importlib.metadata.version, importlib.metadata.Distribution.version and importlib.metadata.Distribution.name return None in this situation.
I couldn't see any suggestion in the stdlib docs (https://docs.python.org/3.10/library/importlib.metadata.html#distribution-versions) that this was possible. (Aside: it'd be great if the docs mention that PackageNotFoundError is raised if a package is not installed.)
No-one in their right mind should do step 4 willingly, but I have seen it happen in the wild (matrix-org/synapse#12223). We suspected a botched backup or similar was to blame.
I'm not familiar with all the machinery of Python package management, but I think I'd expect there to be a PackageNotFoundError raised in this situation? (I can imagine a package that doesn't declare its version, where
version()returningNonemight make sense; but that feels odd.) Is the behaviour as intended?It looks like this might be related to python/importlib_metadata#371?
jaraco commentedon Mar 18, 2022
Thanks for the report.
Yes, the issues are related, where .version and .name returning None are specific manifestations of the metadata not having that key and the behavior being ill-defined.
I haven't yet decided if metadata items being undefined should result in None or raise an Exception (maybe KeyError).
For the specific case of a missing Name or Version, however, the packaging spec says that these fields are required (https://packaging.python.org/en/latest/specifications/core-metadata/#core-metadata-specifications), so it may be reasonable for the behavior when the specification is not met that the resulting behavior would be undefined (i.e. importlib.metadata should be able to assume the specification). It's outside the scope of importlib.metadata to detect, report, and repair invalid metadata. I would welcome and even encourage a third-party package to take on the responsibility of validating all distributions in an environment and reporting on non-compliant aspects.
In that sense, the type declaration is correct.
.nameand.versionshould always returnstror raise an exception.This additional example leads me stronger toward the position that
.metadata[missing]should raise a KeyError, which would also fix this issue.I'd also argue that if the metadata file is missing altogether, that should perhaps be a different error. That is, missing metadata is different from null metadata. Right now, the two are indistinguishable from the interface.
That doesn't sound quite right to me. If there's a
.dist-infodirectory, that implies a package is present. e.g.:I'm going to ponder this one some more and probably address the
.metadataissue(s) first before making any pronouncements on the best approach here.rgommers commentedon Jun 23, 2022
jaraco commentedon Jun 23, 2022
Hi Ralf. The issue you describe is different, so I'll move it to another bug.
sswam commentedon Dec 16, 2022
FWIW, I noticed that I had two torch directories under
/usr/local/lib/python3.10/dist-packages:importlib_metadata.version("torch")was retuningNonein this scenario. I think it was looking at the directory which only had the REQUESTED file.After I removed that
torch-1.12.1+cu116.dist-infodirectory, it fixed the problem, i.e. now:importlib_metadata.version("torch") == '1.13.1+cu116'jaraco commentedon Apr 16, 2023
This issue is being addressed in python/importlib_metadata#371, the first stage (deprecation) being rolled into CPython in 3.12 as #103584.
Skip distributions with incomplete metadata
Skip distributions with incomplete metadata
Skip distributions with incomplete metadata (#2231)
earonesty commentedon Oct 19, 2023
pkg_resources.get_distribution("torch").version always works, even if deprecated,... should be used if other methods fail
Using a most awful hack, monkeypatch a workaround for python/cpython#…
Using a most awful hack, monkeypatch a workaround for python/cpython#…