#754 Should python3-foo obsolete python2-foo (when python2-foo is removed)?
Closed: rejected 5 years ago Opened 6 years ago by churchyard.

Guideline page needing clarification:

https://fedoraproject.org/wiki/Packaging:Guidelines#Renaming.2FReplacing_Existing_Packages

If a package supersedes/replaces an existing package without being a sufficiently compatible replacement as defined above, use only the Obsoletes: line from the above example.

See also (aka place where I'd like to see the clarification):

https://fedoraproject.org/wiki/Packaging:Python#Multiple_Python_Runtimes

Mirroring the policy for regular packages, the Python-version-specific subpackages of your package MUST NOT be removed in a release branch of Fedora.

Explanation

As far as I understand it, if python2-foo subpackage is removed from python-foo, and only python3-foo is kept, proper obsoletes need to be added to the python3-foo package in order to provide a clean upgrade path. However @praiskup raised the following question during a pull request review:

Still, python3-foo doesn't supersede nor replace python2-foo, so I don't think this applies.
Could we somehow bake this into Python guidelines first, please?

In my opinion, python3-foo does supersede python2-foo.

Should python3-foo obsolete python2-foo < $VERSION-$RELEASE (and python-foo < $VERSION-$RELEASE if needed) when python2-foo is removed? If not, how should a clean upgrade path be achieved?


Additional question emerged from the discussion:

Is it OK to obsolete python2-foo < %{version}-%{release} (not hardcoded) if the exact version is unknown (because it depends on external condition (such as RHEL > 7 || Fedora > 30))?


A bit related question: Is 'python3' package going to obsolete 'python2' package?

If/when python2 is removed, than I'd say yes, by the same logic.

No. Obsoleting is only applicable when a package is an ABI/API-compatible replacement.
This does not apply to python2->python3 changes.

Obsoleting is only applicable when a package is an ABI/API-compatible replacement.

Based on what rule?

When Django was renamed to python-django, Django's version was updated. It was not ABI/API compatible, but obsoleted anyway. fedora-obsolete-packages is not ABI/API compatible with anything, yet it obsoletes plenty packages.

Providing python2-whatever says that you're providing the "whatever" library for a python2 environment, that can be installed in parallel with "whatever" for a python3 environment. Adding the obsoletes breaks the second part of that. Since you're talking about just adding an Obsoletes and not a Provides, it's conceivably possible to make Fedora internally consistent with all of these tags, but it makes things more difficult for third-party repos or packages, and adds a weird untruth to spec files.

Removing old python2 packages should be handled the way removing any other type of unused package is: leaving the spec file alone and allowing dnf to clean up unused dependencies.

Removing old python2 packages should be handled the way removing any other type of unused package is: leaving the spec file alone and allowing dnf to clean up unused dependencies.

I don't agree. See How to remove a package at end of life:

While not strictly part of the process, please consider what will happen to systems which have the now-retired packages installed. Generally such packages will simply remain on the system as it is updated, becoming increasingly outdated.

Please follow relevant packaging guidelines here if another package will be providing similar or identical functionality to the retired package, or if it is necessary that the package be removed from end-user systems on system updates.

Emphasis on similar by me.

Note that huge precedence here is https://fedoraproject.org/wiki/Changes/Django20 - a first round of "mass" python2 packages removal from Fedora. Obsoletes were added. But that was driven mostly by me, so obviously it's biased by my understanding of the guidelines.

Example change is https://src.fedoraproject.org/rpms/python-django-ajax-selects/pull-request/1#request_diff

We also added plenty obsoletes to django itself for all the retired packages:

https://src.fedoraproject.org/rpms/python-django/blob/2173e47dc020ddc45f9b6a43e4fc04292ae861b4/f/python-django.spec#_87

The motivation here was to provide a clean upgrade path, not to say Django brings functionality of all of those packages (it clearly does not).

From the POV of the whole distro, something needs to add those Obsoletes. Without them, users cannot upgrade properly and will have to explicitly uninstall packages before e.g. dnf system-upgrade is able to proceed.

There are essentially two choices where to add it:

  1. individual python3 packages
  2. fedora-obsolete-packages

I think 1. is just easier to implement, because the maintainers of individual python packages can add the Obsoletes when dropping the python2 subpackage. The dnf log is also nicer: "removing python2-foo, obsoleted by python3-foo" is self-explanatory, while "removing python2-foo, obsoleted by fedora-obsolete-packages" not so much.

Adding the obsoletes breaks the second part of that. Since you're talking about just adding an Obsoletes and not a Provides, it's conceivably possible to make Fedora internally consistent with all of these tags, but it makes things more difficult for third-party repos or packages, and adds a weird untruth to spec files.

Yes, this makes it harder for third parties. To alleviate this somewhat, the Obsoletes must be versioned, so that the third parties can just bump the version or release to allow installation of their packages in parallel with the python3 packages.

FWIW, I don't think we should be dropping python2 subpackages without a good reason. In particular as long as upstream supports python2, it should be built in Fedora too.

From the POV of the whole distro, something needs to add those Obsoletes...

Exactly!

FWIW, I don't think we should be dropping python2 subpackages without a good reason. In particular as long as upstream supports python2, it should be built in Fedora too.

It's up to the maintainer when to remove the python2 subpackage (if done in rawhide). And while we cannot "force" the removal, we can ask for it. Long story short, python2 EOLs in less than 2 years and we intent to orphan it. It has some thousands dependent packages, so we need to start removing them sooner than later. We will send an e-mail about this to devel@ soon (it's being crafted), so we can continue this discussion there.

FWIW, I don't think we should be dropping python2 subpackages without a good reason. In particular as long as upstream supports python2, it should be built in Fedora too.

As long as anyone wants to support python2 in Fedora, it will be built in Fedora too. You are welcome to take over python2 maintainership and support it even after upstream EOL. (*)
But the current maintainers would like to get rid of it, with as little disruption as possible, which means removing dependent packages gradually. That will take a few years. We need to start now to avoid breakage when python2 is orphaned.

* (We actually do just that for python2.6, with specific caveats, and don't mind doing something similar after python2.7's upstream EOL.)

From the POV of the whole distro, something needs to add those Obsoletes...

If the (sub)package get's retired, it is just retired, those are not installable from repos. What's the real problem in having some dangling python2-* packages installed after upgrading to fedora which doesn't have python2 package (by default)?

It will "hold" the python2 package via the dependency on it. It can break upgrades. And if not, user will have a unmaintained insecure Python interpreter on her machine for who knows how long.

Example of failed upgrade due to not obsoleted packages is at https://bugzilla.redhat.com/show_bug.cgi?id=1455585

I would naively say that broken upgrade problem in such case is task for dnf+friends, even if we had to special-case the "python2" (once the time comes).
Also, isn't the 1455585 a bit different issue? Because at that time we kept python3 package, but it has been updated to provide different abi. For python2 removal, the python2 abi will be retired at the same time as python2-foo.

But yeah, I'm convinced now that Obsoletes: probably good-enough work-around, and as zbyszek said it needs to be versioned, and it needs to of fixed version (not dynamic Obsoletes: ... <= %version). It also means that the Obsoletes tag can not be used sooner than once the python2-foo packages is really retired...

I would naively say that broken upgrade problem in such case is task for dnf+friends, even if we had to special-case the "python2" (once the time comes).

No, not really. We (as in people dealing with fedup, dnf upgrade --releasever, then dnf system-upgrade, etc.) have been through this many times, and adding Obsoletes is the solution we settled on. Let's not revisit this thorny issue here.

it needs to of fixed version (not dynamic Obsoletes: ... <= %version)

That's what the guidelines say already: "$obsEVR is an (Epoch-)Version-Release tuple arranged so that there is a clean upgrade path but without gratuitously polluting the version space upwards. You usually do not use macros for this as you're simply trying to advance beyond the last known release under the old name."

It also means that the Obsoletes tag can not be used sooner than once the python2-foo packages is really retired

Yes!

Let's not revisit this thorny issue here.

I don't understand what's wrong on revisiting anything, upgrades suck (one example for everything, packages should be upgraded to newer --releasever, even though ENVR is smaller).

But OK, at least I don't mind now, since the time is not there yet in Fedora. But once we are there, I would really expect some more automatic way to obsolete python2 subpackages properly, ideally supported by python guys -- and without the %if hell... Say

# E:N-V-R -> the last version of python2-foo we provided in fedora
%{?python2_obsolete python-foo E:N-V-R}

Or maybe %global python2_obsoletes E:N-V-R, since most of the packages already use %python_provides.

Btw., consider Fedora N has python-foo of version X, and Fedora N+1 has python-foo of version X, too. So packager set's the Obsoletes: python2-foo < X.fcN, ... but later then, Fedora N receives an update to say python-foo of version X+1 (but release flag bump is enough). Packager can then very easily forget to bump the Obsoletes: flag to X+1. ... this is long time yum/dnf weakness which can be mitigated by setting higher repo priority during upgrades, or by really careful package maintenance.. And we as a distro shouldn't depend on the latter.

Added the following question to the issue description:

Is it OK to obsolete python2-foo < %{version}-%{release} (not hardcoded) if the exact version is unknown (because it depends on external condition (such as RHEL > 7 || Fedora > 30))?

Or maybe %global python2_obsoletes E:N-V-R, since most of the
packages already use %python_provides.

Actually just yesterday, I raised an idea of extending %python_provides
macro to automatically issue Obsoletes in python3-X context in an
exchange with Miro about dropping python2-X package. But I hadn't
realized that the version to compare with might rather be fixed, not
dynamic per current version/release.

If it'd rather be fixed (which is exactly what the OP's "additional
question" is to address, IIUIC), then indeed such a fixed piece of
information need to be provided explicitly, e.g. as suggested.


To elaborate a bit, my idea was in line with preserving once
established knowledge about how to deal with python2-X package
(until the final EOL of Python 2, perhaps, if the support is not
dropped earlier in upstream, indeed; reason for that is, e.g.,
one could still build python2-X locally if desperate enough).
For that

%bcond_with python2

with respective conditionals seems to be the most natural choice.
But apparently, this leaves no extra annotation around for
%python_provides to utilize so as to emit Obsoletes
appropriately.

Hence I thought, inspired with Petr's %py2_bcond_if idea
that we could wrap that %bcond_with with some extra handling,
notably with an annotation serving as an extra input to
%python_provides, under a facade of a new (for instance)
%python2_bcond macro.

If indeed the baseline for Obsoletes needs to be static, it could
take the correct version/release as an argument. It could also take
a switch instead meaning "unless Python 2 is frowned upon (until then
build python2-X as usual unless overridden with --without-python2)",
which would then hopefully be easy enough to convert to suitable
version/release specification programatically in a targeted mass
rebuild (just pick the current version/release after the likewise
automated release bump) over the packages using such a provision.

Can we stay focused on the guideline clarification please and invent magical automation on top of it after it gets resolved?

Metadata Update from @churchyard:
- Issue tagged with: meeting

5 years ago

This is still being problematic in PR reviews. Tagged with meeting to talk about it this week.

We discussed this at this weeks meeting (https://meetbot-raw.fedoraproject.org/fedora-meeting-1/2018-04-19/fpc.2018-04-19-16.00.txt):

While obsoleting python2- from python3- solve the technical issue (of upgrades). It does not make sense from a semantical point of view.
If the package should be removed on upgrades. Then it should be obsoleted by package fedora-obsolete-packages.
This will give a place for people who (for some theoretical reason) wants to keep the obsolete python2-foo package while having up to date python3-foo package. They can just remove fedora-obsolete-package and can have both python2- and python3- together.
At the same time, this solution will remove pythn2-* package on dist-upgrade for most users.

This issue is now making it down to fedora-obsolete-packages, which itself has sort of turned into a mess. This one landed in my lap: https://bugzilla.redhat.com/show_bug.cgi?id=1578359

Getting someone to add a simple statement of what is broken to that bug seems to be difficult. But if there are dependency problems on upgrade caused by stray python2 packages then fedora-obsolete-packages provides a reasonable means to obsolete them. But note in that ticket how someone made the statement that rawhide should have no python2 packages currently. I'm not sure if that level of misunderstanding is pervasive.

In any case, I do expect that fedora-obsolete-packages will probably need to grow a whole lot of python2 dependencies as things progress. I don't have problems adding those if I can get adequate documentation of the breakage.

Alternately, why does dnf system-upgrade not use --allowerasing by default, or when there are errors as a second pass after prompting the user? Would that get us out of more problematic situations than adding obsoletes everywhere?

We discussed this at this weeks meeting (http://meetbot.fedoraproject.org/fedora-meeting-1/2018-05-17/fpc.2018-05-17-16.00.txt):

  • x754 Should py3-foo obsolete py2-foo (when py2-foo is removed)?
    (geppetto, 16:24:03)
  • LINK: https://bugzilla.redhat.com/show_bug.cgi?id=1578514
    (mhroncok, 16:29:05)
  • mhroncok to help tibbs co-maintain fedora-obsolete-packages
    (geppetto, 16:57:48)
  • We acknowledge that there are likely to be a lot of py2 packages
    added to fedora-obsolete-packages in the near future (geppetto,
    16:58:48)

Metadata Update from @james:
- Issue close_status updated to: rejected
- Issue status updated to: Closed (was: Open)

5 years ago

The resolution from the meeting was the following:

When removing py2 package, don't obsolete it from py3, but rather obsolete it from fedora-obsolete-packages but only if keeping that package installed is likely to cause problems on upgrades.

Can we get a statement that the python2- version of a package MUST NOT be obsoleted by its python3- counterpart? Among other things, someone doing this resulted in https://bugzilla.redhat.com/show_bug.cgi?id=1577394 which is caused by python3-django-pipeline and python3-django-haystack trying to install their python3 counterparts which starts a domino effect of problems.

I'm not sure such a blanket statement would be correct. Are there no situations where it makes sense for the python3 package to obsolete the python2 one? I don't know. That certainly wouldn't be the common case.

The general idea is that if something really has to be obsoleted and there's no good package to do the obsoleting then you use fedora-obsolete-packages. That's what the rules have been and we haven't changed that. If someone made a determination that there was a good package for that and it turned out that they were wrong, well, then they were wrong and the bug gets fixed up.

Looking at that ticket it almost seems as if dnf is taking Obsoletes: to also mean Provides:. If so that would be rather unfortunate. But I am starting to reach the conclusion that there really is no good solution here, and certainly there's no blanket directive we can issue other than to try not to obsolete anything and then if something must be obsoleted, to do that in fedora-obsolete-packages. Anything else seems to have the end result of dnf trying to install packages that weren't there before, when we only want things to be removed.

I'm not sure such a blanket statement would be correct. Are there no situations where it makes sense for the python3 package to obsolete the python2 one? I don't know. That certainly wouldn't be the common case.

OK, I suppose that if the package's primary purpose was to provide /usr/bin/something, then obsoleting it would be the right choice. I can't actually think of any other examples besides that where obsoleting by an incompatible package would make sense. If the goal was simply to eliminate python2 packages from the system, then they should be obsoleted by fedora-obsolete-packages at the packager's discretion or else just wait for the eventual day when the python2 package itself is obsoleted and removed.

The general idea is that if something really has to be obsoleted and there's no good package to do the obsoleting then you use fedora-obsolete-packages. That's what the rules have been and we haven't changed that. If someone made a determination that there was a good package for that and it turned out that they were wrong, well, then they were wrong and the bug gets fixed up.
Looking at that ticket it almost seems as if dnf is taking Obsoletes: to also mean Provides:. If so that would be rather unfortunate. But I am starting to reach the conclusion that there really is no good solution here, and certainly there's no blanket directive we can issue other than to try not to obsolete anything and then if something must be obsoleted, to do that in fedora-obsolete-packages. Anything else seems to have the end result of dnf trying to install packages that weren't there before, when we only want things to be removed.

Well, DNF will interpret Obsoletes and Obsoletes with Provides differently. In the Obsoletes case, if the package is already installed, it will opt to remove it in favor of the Obsoleting package. However, without Provides it should not attempt to install it on request. So without Provides, a dnf install python2-foo should fail, but a dnf update python2-foo would replace it with python3-foo if it was already present.

At least, I'm pretty sure that's how the logic works. @dmach or @ignatenkobrain could probably speak with more certainty on that.

On 05/22/18 14:33, Stephen Gallagher wrote:

If the goal was simply to eliminate python2 packages from the system, then hey should be obsoleted by fedora-obsolete-packages at the packager's discretion

Sounds good to me.

Are we fine giving that as a general recommendation for packages that
don't have special considerations like providing shell commands?
There will be thousands of those.

or else just wait for the eventual day when the python2 package itself is obsoleted and removed.

Can we not recommend this? I want python2 to fade away into obscurity,
not to forcefully remove it with thousands of sudden FTBFSs.
I want to remove leaves first.

or else just wait for the eventual day when the python2 package itself is obsoleted and removed.

Even if python2 itself is obsoleted, dnf will not know that python2 subpackages that depend on it are in any way special, so users will have exactly the same problem during the upgrade ("some packages could not be upgraded..."), just at a bigger scale.

The resolution from the meeting was the following:
When removing py2 package, don't obsolete it from py3, but rather obsolete it from fedora-obsolete-packages but only if keeping that package installed is likely to cause problems on upgrades.

That resolution is disappointing. If this was followed by clear checklist what "likely to cause problems" means, maintainers would know what to do. But by leaving that unspecified, we are asking maintainers to do the research on their own.

Login to comment on this ticket.

Metadata