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

Fix isolated environment scripts path on Debian #11623

Merged
merged 4 commits into from
Jan 4, 2023

Conversation

dnicolodi
Copy link
Contributor

The scripts path was looked up passing explicitly the scheme to be used using "nt" on Windows and "posix_prefix" everywhere else. However, when the isolated build environment is created, packages are installed using the default scheme for the platform. On most platforms this works because normally "nt" and "posix_prefix" are the default schemes.

However, Debian customizes sysconfig to use a "posix_local" scheme by default and under this scheme the scripts path does not match the one of the "posix_prefix" scheme. This results in scripts installed as part of the build dependencies not to be found during the build, as reported here mesonbuild/meson-python#109 and here https://bugs.debian.org/1019293.

The problem can be solved omitting to specify a scheme when looking up the scripts path. To future proof the path lookup, use the "venv" scheme if available as done in #11598. For uniformity use similar functions as used to lookup the library paths.

@uranusjr
Copy link
Member

You also need a corresponding function for distutils; it’d be enough to simply move the old logic there since nobody on old systems are complaining about that being wrong.

@dnicolodi
Copy link
Contributor Author

You also need a corresponding function for distutils

Unless there is some magic trick I don't see, the existing code uses sysconfig unconditionally. Thus I thought adding a distutils fallback was not necessary.

@uranusjr
Copy link
Member

uranusjr commented Nov 29, 2022

You’re right, now I’m wondering why no-one reported any issues about it… but I’m not going to argue with success.

Since this logic is the same across both backends, can you simply move the logic to locations/__init__.py and get rid of the unnecessary call to _sysconfig?

@dnicolodi
Copy link
Contributor Author

I think there are not many packages that depend on scripts installed as build dependencies out there. This came up in packages using meson-python as pep517 backend. meson-python installs meson and ninja if required as build dependencies. On which platforms is pip still using installation paths from distutils?

I decided to keep the implementation next to the implementation of get_isolated_environment_lib_paths() to make it more evident that the two should be most likely kept in sync. I don't think the overhead of one more function call matters at all here. However, I don't have a strong opinion about this, and I can move the implementation, if you like it more that way.

@uranusjr
Copy link
Member

On which platforms is pip still using installation paths from distutils?

See docstrings on functions and constants near the top of the __init__.py.

I decided to keep the implementation next to the implementation of get_isolated_environment_lib_paths() to make it more evident that the two should be most likely kept in sync

If the goal is to keep things in sync, we should probably merge the two functions. Something like get_isolated_environment_scheme() that returns a scheme object (like get_scheme() in the same module) so the logic and results always stay together.

@dnicolodi
Copy link
Contributor Author

See docstrings on functions and constants near the top of the __init__.py

Which __init__.py?

I reworked the implementation slightly. Let me know if you like this better.

@dnicolodi
Copy link
Contributor Author

ping?

@uranusjr
Copy link
Member

uranusjr commented Dec 6, 2022

You didn’t answer my question earlier. Is it viable to merge get_isolated_environment_bin_path and get_isolated_environment_lib_paths into one function?

@dnicolodi
Copy link
Contributor Author

Have you seen the changes in the last push? The implementation has been merged into a single function. I don't think that restructuring the code any further makes it easier to read or understand. If you think differently, please let me know and I'll restructure it. However, this sort of cleanup IMHO does not belong into a PR that is fixing a very real and very serious bug.

@uranusjr
Copy link
Member

uranusjr commented Dec 6, 2022

But why do you keep the two functions, instead of simply exposing get_isolated_environment_paths in locations/__init__.py and calling it from other modules? The part I really don’t understand is the insistence on the extra function call layer, either in the earlier or the current implementation.

@dnicolodi
Copy link
Contributor Author

dnicolodi commented Dec 6, 2022

Please note that the extra function call layer was already there for get_isolated_environment_lib_paths(). I simply keep the same code structure for get_isolated_environment_bin_path(). I don't understand why there needs to be a locations._sysconfig module either, but I just followed what was done before. I can change that, if you like, but maybe a more cohesive refactoring is necessary, and it would be outside the scope of this PR.

@dnicolodi
Copy link
Contributor Author

Note that get_isolated_environment_lib_paths() has two implementations, one in locations._sysconfig and one in locations._distutils that's the reason for the indirection. get_isolated_environment_bin_path() does not have a distutils implementation, thus we get what seems to be a pointless redirection to keep the symmetry between the two functions.

@dnicolodi
Copy link
Contributor Author

I don't see a way to easily simplify this further without bigger reorganization of the code or without loosing the obvious symmetry between get_isolated_environment_lib_paths() and get_isolated_environment_bin_path().

@pradyunsg
Copy link
Member

This is https://discuss.python.org/t/linux-distro-patches-to-sysconfig-are-changing-pip-install-prefix-outside-virtual-environments/18240 and (personally) I'd much rather we fix this either via the redistributors unbreaking their patches or #10720.

@dnicolodi
Copy link
Contributor Author

While I also think #10720 is probably the right solution in the long run (that PR seems stalled and in the meanwhile we need a solution that works) this PR fixes an instance of pip using the sysconfig API incorrectly. The fact that using the API correctly fixes pip on Debian can be seen as incidental (and I don't see what is wrong with the way in which Debian customizes the installation path scheme, in this case).

@pradyunsg
Copy link
Member

Bah, I meant to mention #11619.

That said, I do agree with your point that improving the custom isolation to be less broken is likely still a good idea.

@dnicolodi
Copy link
Contributor Author

I see that #11619 proposes to add the venv-based isolation as an option and not as the only implementation. Fixing the current implementation is thus still required. Is there any remaining issue that needs to be addresses in this PR before merging?

It would be great to have a 22.3.2 release with this fix and #11598 to fix pip on Homebrew and on Debian.

@pfmoore
Copy link
Member

pfmoore commented Dec 6, 2022

Rge release 22.3 cycle is now complete, so any changes would now have to wait for 23.0.

@dnicolodi
Copy link
Contributor Author

Do we really need keep pip broken on Debian till February?

@pfmoore
Copy link
Member

pfmoore commented Dec 6, 2022

This is no different than any other bug fix that gets implemented between releases.

@dnicolodi
Copy link
Contributor Author

Indeed. But the issue is unrelated to this PR. If you revert to the commit before the merge of this PR you get the same error. I'm looking at this issue.

@stefanor
Copy link
Contributor

Yeah, looks like the regression comes from 19e8022 (#11598)

@dnicolodi
Copy link
Contributor Author

I suspected it. I'm trying to understand why that patch breaks pip on Debian.

@stefanor
Copy link
Contributor

Because packages were installed into overlay/local/lib/python3.11/dist-packages (with the Debian posix_local scheme), but sitecustomize.py has overlay/lib/python3.11/site-packages, where it used to have overlay/local/...

@dnicolodi
Copy link
Contributor Author

That much was obvious. Understanding why the paths are resolved like that is the real question.

@stefanor
Copy link
Contributor

Previously get_prefixed_libs() didn't specify a scheme, so it used to use the default scheme.

Pip's isolated environment isn't a virtualenv (yet?), so it doesn't necessarily use the venv layout.

jollaitbot pushed a commit to sailfishos-mirror/dbus-python that referenced this pull request Jan 20, 2023
…iner

Signed-off-by: Simon McVittie <smcv@collabora.com>
@stefanor
Copy link
Contributor

Confirmed that patching out the venv branch in #11598 will give a pip that resolves the Debian bug here.

@dnicolodi
Copy link
Contributor Author

Sure, but it then pip breaks on Homebrew. I wonder if there is an incarnation of this that works everywhere or the customisations Debian and Homebrew do to sysconfig are incompatible.

@stefanor
Copy link
Contributor

stefanor commented Jan 20, 2023

I don't know exactly what behaviour they're referring to in:
https://github.com/Homebrew/homebrew-core/blob/5c70586729909455ef0ff01f835e0d8821a67e8d/Formula/python%403.11.rb#L70

But I imagine the right thing to do is to have pip select the posix_prefix scheme when a prefix is specified (And I'm sure there's a lot more detail here, that I'm handwaving away). Both Debian and Homebrew are relying on schemes to imply prefixes, which is problematic.

I'm not speaking authoritatively for Debian here: I kind of hope that the replacement of setup.py files by PEP517 installers means we can get away from some of the sysconfig scheme customizations that we do. If all package installation is centralized in pip (and a few similar tools), then those can get patches to support PEP-668, and we won't need things like the posix_local sysconfig scheme.

@stefanor
Copy link
Contributor

I think on homebrew the venv scheme just happens to match what pip install --prefix /tmp/foo is doing. But on Debian it isn't.

@pradyunsg
Copy link
Member

@stefanor Has Debian added PEP-668's EXTERNALLY-MANAGED file on testing, to Python?

@stefanor
Copy link
Contributor

That's a good point. Now's the time to do it, before we freeze!

dnicolodi added a commit to dnicolodi/pip that referenced this pull request Jan 21, 2023
Use the same code to determine isolated environment paths at
dependency install time and at environment setup time. We do not care
about the exact paths but the paths needs to be consistent at package
installation time and environment setup.

This should fix all issues observed on platforms that customize the
installation schemes, such as Debian and Homebrew, where dependency
installation and isolated build environment setup resolved to
different paths.

See pypa#11598 and pypa#11623.
dnicolodi added a commit to dnicolodi/pip that referenced this pull request Jan 21, 2023
Use the same code to determine isolated environment paths at
dependency install time and at environment setup time. We do not care
about the exact paths but the paths needs to be consistent at package
installation time and environment setup.

This should fix all issues observed on platforms that customize the
installation schemes, such as Debian and Homebrew, where dependency
installation and isolated build environment setup resolved to
different paths.

See pypa#11598 and pypa#11623.
dnicolodi added a commit to dnicolodi/pip that referenced this pull request Jan 21, 2023
Use the same code to determine isolated environment paths at
dependency install time and at environment setup time. We do not care
about the exact paths but the paths needs to be consistent at package
installation time and environment setup.

This should fix all issues observed on platforms that customize the
installation schemes, such as Debian and Homebrew, where dependency
installation and isolated build environment setup resolved to
different paths.

See pypa#11598 and pypa#11623.
@dnicolodi
Copy link
Contributor Author

@stefanor Can you please give #11740 a try? It works in my tests.

dnicolodi added a commit to dnicolodi/pip that referenced this pull request Jan 21, 2023
Use the same code to determine isolated environment paths at
dependency install time and at environment setup time. We do not care
about the exact paths but the paths needs to be consistent at package
installation time and environment setup.

This should fix all issues observed on platforms that customize the
installation schemes, such as Debian and Homebrew, where dependency
installation and isolated build environment setup resolved to
different paths.

See pypa#11598 and pypa#11623.
@stefanor
Copy link
Contributor

@stefanor Can you please give #11740 a try? It works in my tests.

Yeah works for me.

@stefanor Has Debian added PEP-668's EXTERNALLY-MANAGED file on testing, to Python?

Proposed that here. https://salsa.debian.org/cpython-team/python3/-/merge_requests/28
Of course that would make the specific bug that brought me here moot, because pip won't let you install packages (into --user or the system), on an EXTERNALLY-MANAGED python. I'm guessing we'll see people recommending to delete that file, soon :)

@dnicolodi
Copy link
Contributor Author

@stefanor Thank you for testing.

@dnicolodi
Copy link
Contributor Author

dnicolodi commented Jan 21, 2023

Of course that would make the specific bug that brought me here moot, because pip won't let you install packages (into --user or the system), on an EXTERNALLY-MANAGED python. I'm guessing we'll see people recommending to delete that file, soon :)

You could not even install a pip that fixes this issue 😃

dnicolodi added a commit to dnicolodi/pip that referenced this pull request Jan 21, 2023
Use the same code to determine isolated environment paths at
dependency install time and at environment setup time. We do not care
about the exact paths but the paths needs to be consistent at package
installation time and environment setup.

This should fix all issues observed on platforms that customize the
installation schemes, such as Debian and Homebrew, where dependency
installation and isolated build environment setup resolved to
different paths.

See pypa#11598 and pypa#11623.
dnicolodi added a commit to dnicolodi/pip that referenced this pull request Jan 30, 2023
Use the same code to determine isolated environment paths at
dependency install time and at environment setup time. We do not care
about the exact paths but the paths needs to be consistent at package
installation time and environment setup.

This should fix all issues observed on platforms that customize the
installation schemes, such as Debian and Homebrew, where dependency
installation and isolated build environment setup resolved to
different paths.

See pypa#11598 and pypa#11623.
dnicolodi added a commit to dnicolodi/pip that referenced this pull request Jan 30, 2023
Use the same code to determine isolated environment paths at
dependency install time and at environment setup time. We do not care
about the exact paths but the paths needs to be consistent at package
installation time and environment setup.

This should fix all issues observed on platforms that customize the
installation schemes, such as Debian and Homebrew, where dependency
installation and isolated build environment setup resolved to
different paths.

See pypa#11598 and pypa#11623.
dnicolodi added a commit to dnicolodi/pip that referenced this pull request Jan 30, 2023
Use the same code to determine isolated environment paths at
dependency install time and at environment setup time. We do not care
about the exact paths but the paths needs to be consistent at package
installation time and environment setup.

This should fix all issues observed on platforms that customize the
installation schemes, such as Debian and Homebrew, where dependency
installation and isolated build environment setup resolved to
different paths.

See pypa#11598 and pypa#11623.
inmantaci pushed a commit to inmanta/inmanta-core that referenced this pull request Jan 31, 2023
Bumps [pip](https://github.com/pypa/pip) from 22.3.1 to 23.0.
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a href="https://github.com/pypa/pip/blob/main/NEWS.rst">pip's changelog</a>.</em></p>
<blockquote>
<h1>23.0 (2023-01-30)</h1>
<h2>Features</h2>
<ul>
<li>Change the hashes in the installation report to be a mapping. Emit the
<code>archive_info.hashes</code> dictionary in <code>direct_url.json</code>. (<code>[#11312](pypa/pip#11312) &lt;https://github.com/pypa/pip/issues/11312&gt;</code>_)</li>
<li>Implement logic to read the <code>EXTERNALLY-MANAGED</code> file as specified in PEP 668.
This allows a downstream Python distributor to prevent users from using pip to
modify the externally managed environment. (<code>[#11381](pypa/pip#11381) &lt;https://github.com/pypa/pip/issues/11381&gt;</code>_)</li>
<li>Enable the use of <code>keyring</code> found on <code>PATH</code>. This allows <code>keyring</code>
installed using <code>pipx</code> to be used by <code>pip</code>. (<code>[#11589](pypa/pip#11589) &lt;https://github.com/pypa/pip/issues/11589&gt;</code>_)</li>
<li>The inspect and installation report formats are now declared stabled, and their version
has been bumped from <code>0</code> to <code>1</code>. (<code>[#11757](pypa/pip#11757) &lt;https://github.com/pypa/pip/issues/11757&gt;</code>_)</li>
</ul>
<h2>Bug Fixes</h2>
<ul>
<li>Wheel cache behavior is restored to match previous versions, allowing the
cache to find existing entries. (<code>[#11527](pypa/pip#11527) &lt;https://github.com/pypa/pip/issues/11527&gt;</code>_)</li>
<li>Use the &quot;venv&quot; scheme if available to obtain prefixed lib paths. (<code>[#11598](pypa/pip#11598) &lt;https://github.com/pypa/pip/issues/11598&gt;</code>_)</li>
<li>Deprecated a historical ambiguity in how <code>egg</code> fragments in URL-style
requirements are formatted and handled. <code>egg</code> fragments that do not look
like PEP 508 names now produce a deprecation warning. (<code>[#11617](pypa/pip#11617) &lt;https://github.com/pypa/pip/issues/11617&gt;</code>_)</li>
<li>Fix scripts path in isolated build environment on Debian. (<code>[#11623](pypa/pip#11623) &lt;https://github.com/pypa/pip/issues/11623&gt;</code>_)</li>
<li>Make <code>pip show</code> show the editable location if package is editable (<code>[#11638](pypa/pip#11638) &lt;https://github.com/pypa/pip/issues/11638&gt;</code>_)</li>
<li>Stop checking that <code>wheel</code> is present when <code>build-system.requires</code>
is provided without <code>build-system.build-backend</code> as <code>setuptools</code>
(which we still check for) will inject it anyway. (<code>[#11673](pypa/pip#11673) &lt;https://github.com/pypa/pip/issues/11673&gt;</code>_)</li>
<li>Fix an issue when an already existing in-memory distribution would cause
exceptions in <code>pip install</code> (<code>[#11704](pypa/pip#11704) &lt;https://github.com/pypa/pip/issues/11704&gt;</code>_)</li>
</ul>
<h2>Vendored Libraries</h2>
<ul>
<li>Upgrade certifi to 2022.12.7</li>
<li>Upgrade chardet to 5.1.0</li>
<li>Upgrade colorama to 0.4.6</li>
<li>Upgrade distro to 1.8.0</li>
<li>Remove pep517 from vendored packages</li>
<li>Upgrade platformdirs to 2.6.2</li>
<li>Add pyproject-hooks 1.0.0</li>
<li>Upgrade requests to 2.28.2</li>
<li>Upgrade rich to 12.6.0</li>
<li>Upgrade urllib3 to 1.26.14</li>
</ul>
<h2>Improved Documentation</h2>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a href="https://github.com/pypa/pip/commit/368c7b4c557e673b05b0f8cffc967d3e333eee19"><code>368c7b4</code></a> Bump for release</li>
<li><a href="https://github.com/pypa/pip/commit/aa94ccadb45d6ee44defea8a82bd5b647ccba799"><code>aa94cca</code></a> Update AUTHORS.txt</li>
<li><a href="https://github.com/pypa/pip/commit/60ce5c0943c303e48f0aed8bce650f725dcd222d"><code>60ce5c0</code></a> Fix the kind of news fragment</li>
<li><a href="https://github.com/pypa/pip/commit/e3e7bc34eb486622ebbb6412afc98ee57fcbff4a"><code>e3e7bc3</code></a> Merge pull request <a href="https://github-redirect.dependabot.com/pypa/pip/issues/11766">#11766</a> from uranusjr/upgrade-pre-commit-isort</li>
<li><a href="https://github.com/pypa/pip/commit/b653b129c56b29ad565886c1f423de89639d20f3"><code>b653b12</code></a> Bump pre-commit isort to 5.12.0</li>
<li><a href="https://github.com/pypa/pip/commit/a2a4feb588edc7233ae262d76b2c7291d6857a31"><code>a2a4feb</code></a> Merge pull request <a href="https://github-redirect.dependabot.com/pypa/pip/issues/11761">#11761</a> from sbidoul/direct-url-hashes-part-3-sbi</li>
<li><a href="https://github.com/pypa/pip/commit/ec7eb6f179866151f148c7695fc773e66b8c3adc"><code>ec7eb6f</code></a> Add version history to inspect and install report docs</li>
<li><a href="https://github.com/pypa/pip/commit/169511e68eb64efff5705305f72b0c53d7bff580"><code>169511e</code></a> Update direct URL hashes examples</li>
<li><a href="https://github.com/pypa/pip/commit/efedf09c4967dcbe3105e3746aaca7bfb55d605f"><code>efedf09</code></a> Merge pull request <a href="https://github-redirect.dependabot.com/pypa/pip/issues/11759">#11759</a> from pradyunsg/fix-keyring-auth</li>
<li><a href="https://github.com/pypa/pip/commit/60a45984404460192067f3990e0258deeeafa636"><code>60a4598</code></a> Merge pull request <a href="https://github-redirect.dependabot.com/pypa/pip/issues/11758">#11758</a> from pradyunsg/vendoring-update</li>
<li>Additional commits viewable in <a href="https://github.com/pypa/pip/compare/22.3.1...23.0">compare view</a></li>
</ul>
</details>
<br />

[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=pip&package-manager=pip&previous-version=22.3.1&new-version=23.0)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually
- `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)

</details>
dnicolodi added a commit to dnicolodi/pip that referenced this pull request Feb 5, 2023
Use the same code to determine isolated environment paths at
dependency install time and at environment setup time. We do not care
about the exact paths but the paths needs to be consistent at package
installation time and environment setup.

This should fix all issues observed on platforms that customize the
installation schemes, such as Debian and Homebrew, where dependency
installation and isolated build environment setup resolved to
different paths.

See pypa#11598 and pypa#11623.
@github-actions github-actions bot locked as resolved and limited conversation to collaborators Feb 6, 2023
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants