Can python package metadata (wheels) explicitly conflict or replace others?

Forgive me if this is obvious, google searching coming up blank…

Do python wheels (package meta) have a mechanism to specify that one package explicitly conflicts or otherwise replaces another?

I’ve run into this because colleagues want to rename both a wheel and python package for the next major release. But I’ve already seen what nasty things happen if you actually manage to have versions 2 and 3 installed in parallel. I actually agree with them; no longer with legacy naming is sometimes worth the heart ache.

What I’d like to do is inform pip/poetry/… that version 3 conflicts with version 2 or, even better, that version 3 (aaa-my-package) replaces version 2 (mypackage-aaa). These are both concepts that apt and dpkg (Debian package management) understand. I can’t find any reference (here to these concepts in Wheel metadata, but I was hoping that I’ve missed something.

It is not possible to have two versions of the same library installed in the same (virtual) environment. Installing version 3 implies that version 2 will be uninstalled.

…Not if it got renamed.

Then no, there is no way to specify such conflicts.

As you seem to have spotted, “Core Metadata” kind of does have some concepts that could help with specifying conflicts (Obsoletes-Dist and Provides-Dist) but no tool (that I know of) implements those Core Metadata fields.

They want to use a different name on PyPI?

Because they can freely change the module names that a user will import when using the code as a library. But the Python packaging system is dependent on the PyPI name to know that something is “a newer version of the same package”.

Not to mention, switching to a different name on PyPI will have different implications for cleaning up the old name and making sure users don’t grab the legacy package by mistake.

I have seen projects that use setuptools to encode this kind of conflict in their setup.py, but it’s not really declarative metadata so much as it is build-time behavior (i.e. this approach doesn’t work for wheels).

In such a case, I would probably rely on a runtime check in the newer library that looks for the older version and issues an error report if it’s present (telling the user to uninstall it), but this has the downside that the conflict is not known at install time, only when the software is actually run.

2 Likes

Okay. I guess the answer to this is going to be to put a runtime check in the root __init__.py of the project in the new V3. That way at least we can warn users something has got messed up.

Hi,

I have a similar issue on the GitHub - stack-of-tasks/pinocchio: A fast and flexible implementation of Rigid Body Dynamics algorithms and their analytical derivatives vs GitHub - mkwiatkowski/pinocchio: pinocchio is a set of extensions to the nose unit testing framework for Python (the latter got the pinocchio name on PyPI first, so the former is currently pin on PyPI, but they both install a pinocchio module)

It would be really useful to be able to declare a conflict in metadata, or to detect file conflicts at install time.

What would be the process to fix this ? Open issues on pip / setuptools ? Write a PEP ?

Runtime check in __init__.py is not a solution I think.

If packages a and b both install a c module, and a provides a c/__init__.py with a runtime check, when the user run pip install b, c/__init__.py is silently overwritten (for me, this is another issue: why wouldn’t pip check for file conflicts ?)

1 Like

In this case, I believe the pin project on PyPI should rename the top-level import to pin, in order to be a good citizen of the Python ecosystem.

As for installers reacting to file conflicts, I guess this has been raised already in the ticket trackers. Maybe a standard could be written to specify the expected behavior, but this would need to come with a lot of effort: getting all installers to agree on the new behavior, writing the code, and so on.