Skip to content
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

Ability to force distutils as installation scheme backend even on Python 3.10 #10647

Closed
1 task done
hroncok opened this issue Nov 9, 2021 · 14 comments · Fixed by #10654
Closed
1 task done

Ability to force distutils as installation scheme backend even on Python 3.10 #10647

hroncok opened this issue Nov 9, 2021 · 14 comments · Fixed by #10654
Labels
project: <downstream> When the cause/effect is related to redistributors type: feature request Request for a new feature
Milestone

Comments

@hroncok
Copy link
Contributor

hroncok commented Nov 9, 2021

What's the problem this feature will solve?

Hello, as you might already know from discussions in https://discuss.python.org/t/pep-632-deprecate-distutils-module/5134/120, in Fedora Linux, we patch our Python to install packages to /usr/local prefix by default. This has been historically done by patching distutils.command.install and recently changed to patching sysconfig._INSTALL_SCHEMES.

I couldn't be happier with pip's move towards the sysconfig way, as it makes everything nicer at the end and allows us to get rid of distutils once for all, as distutils is riddled with traps.

I see that pip made a considerable choice here and only changes the behavior in Python 3.10+. However, this puts us (the Fedora's Python maintainers) into an unfortunate situation:

  • we have updated our "main" Python version to 3.10 in Fedora Linux 35
  • we have only changed our patch to patch sysconfig in Fedora Linux 36+

We realized along the way that the change is not 100% backward compatible and it uncovered several weird bugs in various programs, for example:

Unfortunately, when pip 21.3 was released, Fedora Linux 35 was already beyond code freeze and stability guarantees apply now. As much as I would like to do this change in Fedora Linux 35 as well, I have not found a way to do it that's not potentially disturbing to our users.

What happens now is that when users of Fedora Linux 35 use pip to upgrade pip, it'll start installing packages back to the /usr prefix, which has the potential to brick their systems. We don't have any data, but my assumption is that users who pip install --upgrade pip are more likely to actually sudo pip install something that'll negatively impact the package manager or a similar tool.

pip-installed pip 21.2.3:

[root@dde39f841e21 /]# pip install pello
Collecting pello
  Using cached Pello-1.0.2-py3-none-any.whl (6.0 kB)
Installing collected packages: pello
Successfully installed pello-1.0.2

[root@dde39f841e21 /]# pip uninstall pello
Found existing installation: Pello 1.0.2
Uninstalling Pello-1.0.2:
  Would remove:
    /usr/local/bin/pello_greeting
    /usr/local/lib/python3.10/site-packages/Pello-1.0.2.dist-info/*
    /usr/local/lib/python3.10/site-packages/pello/*
Proceed (Y/n)?

pip-installed pip 21.3:

[root@dde39f841e21 /]# pip install pello
Collecting pello
  Downloading Pello-1.0.2-py3-none-any.whl (6.0 kB)
Installing collected packages: pello
Successfully installed pello-1.0.2

[root@dde39f841e21 /]# pip uninstall pello
Found existing installation: Pello 1.0.2
Uninstalling Pello-1.0.2:
  Would remove:
    /usr/bin/pello_greeting
    /usr/lib/python3.10/site-packages/Pello-1.0.2.dist-info/*
    /usr/lib/python3.10/site-packages/pello/*
Proceed (Y/n)?

This does not happen for Fedora Linux 33 and Fedora Linux 34, as the "main" Python version si 3.9 there. This does not happen to Fedora Linux 36 users, as we patch sysconfig and hence our setup is compatible with pip's decision.

Now, I am not asking you to revert this decision. I am not asking to postpone it to Python 3.11 either. I would merely like to have a way for the Python interpeter to tell pip "hey, I am not ready for this just yet, please use distutils". We would then be able to do this.

Note that we cannot "simply" patch the pip we ship, because it's the upstream pip that the users will likely to install.

Describe the solution you'd like

In here:

https://github.com/pypa/pip/blob/21.3.1/src/pip/_internal/locations/__init__.py#L48

I'd like to be able to able to inject an additional condition that would allow us to use distutils for a bit more time. Something like this:

_USE_SYSCONFIG = getattr(sysconfig, '_PIP_USE_SYSCONFIG', sys.version_info >= (3, 10))

That way, we could set sysconfig._PIP_USE_SYSCONFIG = False in Python 3.10 on Fedora 35.
We could also set sysconfig._PIP_USE_SYSCONFIG = True in Python 3.9 on Fedora 36+ if we would like to have that experience unified across our interpreters.

Alternative Solutions

EDIT: See an alternate solution in #10647 (comment)

An alternate solution is to document this more heavily and discourage users to use sudo pip, but we already do this and it doesn't work :(

Additional context

Fedora's downstream issue: https://bugzilla.redhat.com/show_bug.cgi?id=2014513

Code of Conduct

Thank you for considering this. I am willing to add the code if we agree on the behavior.

@hroncok hroncok added S: needs triage Issues/PRs that need to be triaged type: feature request Request for a new feature labels Nov 9, 2021
@uranusjr
Copy link
Member

uranusjr commented Nov 9, 2021

From the suggestion, I'm assuming a private environment variable would not be good enough, and an interpreter-wide setup is needed instead?

I guess the getattr(sysconfig, ...) approach is the only viable way if that's the case.

Edit: Or maybe we could use the no-manylinux approach? Fedora can put an empty _pip_use_distutils_locations.py file in stdlib and pip would try to import that. This is probably better than having to patch sysconfig.

@uranusjr uranusjr added project: <downstream> When the cause/effect is related to redistributors and removed S: needs triage Issues/PRs that need to be triaged labels Nov 9, 2021
@uranusjr uranusjr added this to the 22.0 milestone Nov 9, 2021
@hroncok
Copy link
Contributor Author

hroncok commented Nov 9, 2021

From the suggestion, I'm assuming a private environment variable would not be good enough, and an interpreter-wide setup is needed instead?

We would need to set the environment variable when sysconfig is imported. It might possibly work, but setting/reading an attribute seems like a saner thing to do.

@hroncok
Copy link
Contributor Author

hroncok commented Nov 9, 2021

Or maybe we could use the no-manylinux approach? Fedora can put an empty _pip_use_distutils_locations.py file in stdlib and pip would try to import that.

I can live with that approach as well.

This is probably better than having to patch sysconfig.

However, we have no trouble patching sysconfig at all. One advantage is that it allows patching in both directions.

@uranusjr
Copy link
Member

uranusjr commented Nov 9, 2021

One advantage is that it allows patching in both directions.

Could you explain this a bit? What would the other direction be?

@hroncok
Copy link
Contributor Author

hroncok commented Nov 9, 2021

I mean this:

That way, we could set sysconfig._PIP_USE_SYSCONFIG = False in Python 3.10 on Fedora 35.
We could also set sysconfig._PIP_USE_SYSCONFIG = True in Python 3.9 on Fedora 36+ if we would like to have that experience unified across our interpreters.

This is also possible to achieve with _pip_use_distutils_locations.py and _pip_use_sysconfig_locations.py, but requires handling the situation when both files exist.

@uranusjr
Copy link
Member

uranusjr commented Nov 9, 2021

I see, that makes sense. A private attribute is best then.

@hroncok
Copy link
Contributor Author

hroncok commented Nov 12, 2021

I am preparing a Python build for Fedora 35 that sets this attribute and will test if it works as expected.

Will submit a draft PR shorty, and later figure out the best approach to make this tested.

@hroncok
Copy link
Contributor Author

hroncok commented Nov 12, 2021

#10654

@jaraco
Copy link
Member

jaraco commented Nov 12, 2021

This issue also affects Debian. Consider this simple Dockerfile:

FROM ubuntu:focal

RUN apt update
RUN apt upgrade -y
RUN apt install -y software-properties-common
RUN apt-add-repository -y ppa:deadsnakes
RUN apt update
RUN apt install -y build-essential wget git

RUN apt install -y python3.10 python3.10-dev python3.10-venv

RUN wget -q https://bootstrap.pypa.io/get-pip.py -O /tmp/get-pip
RUN python3.10 /tmp/get-pip
RUN python3.10 -m pip -V

emits

 > [11/11] RUN python3.10 -m pip -V:                                                                                                                                 
#14 0.392 /usr/bin/python3.10: No module named pip

The basic bootstrap script for pip doesn't leave pip installed.

Edit: I've found I can work around the issue by installing with --user, but that feels like a hack. I'd prefer to install pip (and pip-run and pipx) in the system site packages.

@pradyunsg
Copy link
Member

pradyunsg commented Nov 12, 2021

/cc @doko42 @kitterma @stefanor for visibility, and to put this on their radar.

@pradyunsg
Copy link
Member

One "can-we-be-stricter" question: Do we want to restrict this escape hatch to certain versions of CPython, like <= 3.11 or <= 3.12 or something like that?

The main benefit I see from that is that it'll more clearly communicate that this is something that'll only stay around for a few Python versions. OTOH, I'm also fine with keeping things simple and no having the conditional be overly complicated. :)

@hroncok
Copy link
Contributor Author

hroncok commented Nov 20, 2021

If as pip maintainers you would want to drop distutils support earlier than Python, or at the same planned release, even if it gets postponed in Python, than it makes kinda sense. OTOH my idea was that when this is set and distutils is gone, it will blow up anyway.

@hroncok
Copy link
Contributor Author

hroncok commented Nov 20, 2021

For Fedora, we only need this in 3.10.

@uranusjr
Copy link
Member

I imagine we can't drop distutils support before we drop 3.9 support anyway, and by the time that happens Python should be on 3.14 if the current schedule is kept.

hroncok added a commit to hroncok/pip that referenced this issue Nov 20, 2021
hroncok added a commit to hroncok/pip that referenced this issue Nov 20, 2021
@github-actions github-actions bot locked as resolved and limited conversation to collaborators Dec 21, 2021
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
project: <downstream> When the cause/effect is related to redistributors type: feature request Request for a new feature
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants