New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
In-place copy of a package gets metadata from installed package #94181
Comments
By design, a distribution package and its metadata are loosely-coupled from the Python package(s), for better or for worse. That is, when you
The problem is that by building numpy using old tools and manually patching the environment, you're creating an invalid state (you've upgraded numpy but without replacing the metadata). When you request metadata for You're right that distutils doesn't install Your best bet is to use something like If you wish to programmatically override the search path when resolving the distribution, you could do something like:
I recognize, however, that's not particularly convenient or interesting. Another option could be to uninstall the installed copy of numpy. Then Unfortunately, I don't see any way in the current design for Now that I think about it, maybe there is a cheap and easy way. What if you just create an empty metadata for this in-development package with:
I believe with that, you'll now get either an error or None for Does that provide an adequate workaround? |
I don't think old tools are the issue here. For a pure Python package, you can use
I think the second one is "present" in a physical sense (files on disk in an environment), but there's no way that
I don't really need a workaround. For context, this came up in this thread on the packaging Discourse where it was suggested that
It looks like |
You're right. Now in the case of an imported package detecting its own version, that might be more feasible... because an imported package knows its own context and can limit the search path when discovering metadata. So one could add this to import importlib.metadata as metadata
from os.path import dirname
numpy_where = dirname(dirname(__spec__.origin))
dist, = metadata.distributions('numpy', path=[numpy_where])
__version__ = dist.version That would in most cases resolve the metadata only from the same path where numpy was imported (or fail). I'm not super-confident that But even thinking about Somewhat related, I've stopped (and recommended others to stop) supplying Things would be different if Python's packaging ecosystem had an explicit, direct relationship between modules and their metadata. |
Thanks @jaraco, that all makes sense, and I agree there's only a loose coupling between metadata and imported package. Please feel free to close this as invalid/wontfix if you prefer not to do a consistency check inside
This is the one thing I disagree with. Given that there is only a loose coupling, and that I want to get the actual version corresponding to the imported package, it is clear to me that |
It's not at all obvious to me what sort of consistency check would even be possible. Thinking about the scenario you've described, here's one way it could maybe be done:
This computation is probably prohibitively expensive (definitely not something you'd want to have as an operation that occurs on every import of every top-level package. Which leads me to think the best thing that can be done here is to provide a helper function that implements the technique I described in #94181 (comment), something like: def dist_for_module(name, spec):
where = dirname(dirname(spec.origin))
dist, = metadata.distributions(name, path=[where])
return dist Then numpy could do something like:
Would that be worth exploring? Do you have any other ideas? |
@rgommers I'm keenly interested in your take on my latest proposal. |
Closing as languishing, but feel free to revive the conversation. |
I also think a method to find the metadata for an imported package would be useful. I was using from importlib import machinery, metadata
from pathlib import Path
def module_dist(spec: machinery.ModuleSpec) -> metadata.Distribution:
path = Path(spec.origin)
if spec.parent:
path = path.parent
dists = metadata.distributions(name=spec.name, path=[path.parent])
try:
return next(dists)
except StopIteration as error:
raise metadata.PackageNotFoundError(spec.name) from error The usage is |
I built an in-place version of
numpy
withpython setup.py build_ext -i
(note that that will not have a.dist-info
dir at the root of the repo,distutils
doesn't produce that), and then usedPYTHONPATH
to switch between thenumpy
installed into the conda env and this in-place build:Then open IPython and:
So rather than returning
None
or raising an exception, I'm getting the metadata for the wrong package.Either way would be fine with me, as long as it's not silently returning incorrect metadata. There will be other cases like that other than
numpy
, andPYTHONPATH
is pretty commonly used to switch around packages when developing. A.dist-info
directory may be required to get correct metadata, but it being missing should not cause incorrect results - that's a clear bug.Originally posted by @rgommers in #91216 (comment)
The text was updated successfully, but these errors were encountered: