Skip to content

Fix installations with system Python on Ubuntu/Fedora#31939

Closed
vsoch wants to merge 3 commits intodevelopfrom
packages/py-docutils-bug
Closed

Fix installations with system Python on Ubuntu/Fedora#31939
vsoch wants to merge 3 commits intodevelopfrom
packages/py-docutils-bug

Conversation

@vsoch
Copy link
Copy Markdown
Member

@vsoch vsoch commented Aug 4, 2022

If docutils doesn't have a bin, then don't try to iterate over files in it.

@adamjstewart
Copy link
Copy Markdown
Member

Why would it not have a bin directory? If it's version-specific, we can use @when().

@adamjstewart adamjstewart self-assigned this Aug 4, 2022
@vsoch
Copy link
Copy Markdown
Member Author

vsoch commented Aug 4, 2022

I don't ask the questions, I just am trying to install flux-core and this is the error I hit.

@adamjstewart
Copy link
Copy Markdown
Member

Can you upload the build log here? The fact that part of the installation is just missing is alarming...

@vsoch
Copy link
Copy Markdown
Member Author

vsoch commented Aug 5, 2022

okay so this is weird, the build log looks okay?

spack-build-out.txt

but in my terminal (and it exits on error):

==> Error: FileNotFoundError: [Errno 2] No such file or directory: '/opt/spack/opt/spack/linux-ubuntu22.04-x86_64/gcc-11.2.0/py-docutils-0.18.1-dcncvjgwszuwmanlasey434q3irm7q6d/bin'

/opt/spack/var/spack/repos/builtin/packages/py-docutils/package.py:42, in post_install:
         40    def post_install(self):
         41        bin_path = self.prefix.bin
  >>     42        for file in os.listdir(bin_path):
         43            if file.endswith(".py"):
         44                os.symlink(os.path.join(bin_path, file), os.path.join(bin_path, file[:-3]))

See build log for details:
  /tmp/root/spack-stage/spack-stage-py-docutils-0.18.1-dcncvjgwszuwmanlasey434q3irm7q6d/spack-build-out.txt

@vsoch
Copy link
Copy Markdown
Member Author

vsoch commented Aug 12, 2022

ping we'd like to get this working because it's failing the flux container build

https://github.com/flux-framework/flux-core/runs/7797716827?check_suite_focus=true

ping @trws

@trws
Copy link
Copy Markdown
Contributor

trws commented Aug 12, 2022

I'm trying to repro this now, because trying it outside the container makes it work correctly and actually produces a bin directory no issue.

@trws
Copy link
Copy Markdown
Contributor

trws commented Aug 12, 2022

@adamjstewart, something really strange is going on here. For some reason in this specific container (ubuntu 22.04 based) the directory tree in the prefix is placed under <prefix>/local/{bin,lib} instead of having them at the top level. I have little idea why, the pip command is identical to one that works outside of the container:
'/usr/bin/python3.10' '-m' 'pip' '-vvv' '--no-input' '--no-cache-dir' '--disable-pip-version-check' 'install' '--no-deps' '--ignore-installed' '--no-build-isolation' '--no-warn-script-location' '--no-index' '--prefix=/opt/spack/opt/spack/linux-ubuntu22.04-x86_64/gcc-11.2.0/py-docutils-0.18.1-dcncvjgwszuwmanlasey434q3irm7q6d' '.'

Is this maybe another crazy debianism we need to work around?

@trws
Copy link
Copy Markdown
Contributor

trws commented Aug 12, 2022

It seems that if I switch the flag from --prefix to --target a bin directory is produced correctly, but there is no longer a lib directory, we get bin/ and docutils/.

@vsoch
Copy link
Copy Markdown
Member Author

vsoch commented Aug 12, 2022

And reading their docs it sounds like there is a third location, tools? https://docutils.sourceforge.io/docs/dev/distributing.html

@adamjstewart
Copy link
Copy Markdown
Member

That is quite odd, I wouldn't expect pip to install things to <prefix>/local. It's just this package, no other package, right? I don't see anything suspicious in their setup.py. Does python -s or python -S make a difference here? @pradyunsg any ideas?

@trws
Copy link
Copy Markdown
Contributor

trws commented Aug 12, 2022

Oh that's a good question. Yes it's just that one package, it's really, really odd. I didn't know that --target and --prefix would act that differently either.

@trws
Copy link
Copy Markdown
Contributor

trws commented Aug 12, 2022

-s has no effect, -S makes it so the python can't find pip.

@vsoch
Copy link
Copy Markdown
Member Author

vsoch commented Aug 12, 2022

Why does flux need docutils? Could we make a variant that doesn't require it?

@trws
Copy link
Copy Markdown
Contributor

trws commented Aug 12, 2022

Oh crap, I think I figured out why it's adding the local, but I'm arguing with myself about how to fix it... So, this python is set with its default --root to be /, and the offset from root for prefix to be usr/local, if I specify --root it puts everything at <prefix>/usr/local/.... If I specify --target, the package gets installed into the prefix and forms a bin directory, but it doesn't set the prefix for the top-level bin and lib directories (attempting to set both to the same value causes an error). Setting only the --prefix seems to be equivalent to only overriding the usr portion for some reason, and not the local/ part. I'm betting this is some crazy property of a debian-based distro's system python, but how do we override it and get something that works?

@trws
Copy link
Copy Markdown
Contributor

trws commented Aug 12, 2022

Why does flux need docutils? Could we make a variant that doesn't require it?

Documentation, yes we could have a +docs variant we could turn off, that would drop the deps on docutils and asciidoc.

@vsoch
Copy link
Copy Markdown
Member Author

vsoch commented Aug 14, 2022

To follow up here - we tweaked the variant so it will build without error #32099, but if someone wants the docs they are still going to hit this issue.

@adamjstewart adamjstewart marked this pull request as draft August 14, 2022 17:40
@adamjstewart
Copy link
Copy Markdown
Member

I'm hoping @pradyunsg will have an idea of why only this package is installing to the wrong location and what the best flags to use are.

In the meantime, I marked this PR as a draft since the current PR is more of a workaround than a solution.

@pradyunsg
Copy link
Copy Markdown

Could someone share a clearer explaination of the behaviour you're seeing here, vs what you expected? 🙈

Something that shows the output of pip, as well the final filesystem structure you're seeing would help orient me as well.

$ pip install ...
$ tree ...

Right now, I've just read through the discussion and am not fully sure what the question is and what location is unexpected.

@vsoch
Copy link
Copy Markdown
Member Author

vsoch commented Aug 15, 2022

The package is hard coded to expect docutils to have a bin. It does not, it has a local directory instead.

@adamjstewart
Copy link
Copy Markdown
Member

adamjstewart commented Aug 15, 2022

@pradyunsg we are seeing the same issue as reported in pypa/pip#10978

Expected behavior

We would expect pip install . --prefix=<prefix> to install things to:

<prefix>/bin
<prefix>/lib/pythonX.Y/dist-packages

Actual behavior

Things are being installed to:

<prefix>/local/bin
<prefix>/local/lib/pythonX.Y/dist-packages

This causes all of our assumptions about the install layout to break, including patching of scripts in bin.

@pradyunsg
Copy link
Copy Markdown

pradyunsg commented Aug 15, 2022

Are you using Fedora/RHEL-provided Python, outside of a virtual environment? If so, I'm pretty sure I've seen this before, and it's because of a patch that they've made to Python's site or sysconfig module that changes the installation scheme to be under a local directory when not inside a virtual environment.

https://github.com/fedora-python/cpython/blame/fedora-3.7/Lib/sysconfig.py#L98

I've told at least two folks to report this to Fedora, but I don't know if anyone has reported this to them yet. :)

@vsoch
Copy link
Copy Markdown
Member Author

vsoch commented Aug 15, 2022

Nope it was an ubuntu container.

@trws
Copy link
Copy Markdown
Contributor

trws commented Aug 15, 2022

It's a Debian or Ubuntu one, they use a similar patch sadly, and yes we've complained about their munging of python a number of times, but this is the first time it's broken installation into an explicit prefix.

@pradyunsg
Copy link
Copy Markdown

@pradyunsg
Copy link
Copy Markdown

pradyunsg commented Aug 15, 2022

To confirm whether we're right about this hypothesis, check if posix_local is the name of sysconfig.get_preferred_scheme()?

python -c "import sysconfig; print(sysconfig.get_preferred_scheme())"

@pradyunsg
Copy link
Copy Markdown

I've opened https://discuss.python.org/t/linux-distro-patches-to-sysconfig-are-changing-pip-install-prefix-outside-virtual-environments/18240 because this is broader than just Fedora and... non-trivial.

Assuming this is the source of your issues, my pragmatic suggestion would be to check if there's a single local directory and getting rid of that layer of indirection -- because that shouldn't really be there (and is a bug coming out of the Linux distro patches to Python). That way, when/if this gets fixed in the Linux distros or if Spack is used with a not-distro-patched Python, the logic would gracefully do the right thing with slightly fewer filesystem operations.

@adamjstewart
Copy link
Copy Markdown
Member

I think @trws had the same idea, we can symlink everything in <prefix>/local to <prefix> until this is fixed in each distro. Now if only someone could convince Apple to fix their sysconfig patching...

@spackbot-app spackbot-app bot added build-systems core PR affects Spack core functionality labels Aug 15, 2022
vsoch and others added 2 commits August 15, 2022 16:04
If docutils doesn't have a bin, then don't try to iterate over files in it.
Work around the debian and Fedora bug by symlinking the contents of the
local directory if it appears.
@trws trws force-pushed the packages/py-docutils-bug branch from 422af55 to bedbc2c Compare August 15, 2022 23:04
@trws
Copy link
Copy Markdown
Contributor

trws commented Aug 15, 2022

Basic patch implementing that added here @adamjstewart.

@adamjstewart adamjstewart changed the title Check for docutils bin Fix installations with system Python on Ubuntu/Fedora Aug 15, 2022
local_path = os.path.join(prefix, "local")
if os.path.isdir(local_path) and not os.path.isdir(os.path.join(prefix, "lib")):
for p in os.listdir(local_path):
os.symlink(os.path.join(local_path, p), os.path.join(prefix, p))
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you're going to be thorough, setuptools, wheel, and dozens of other packages that don't use PythonPackage need this as well:

$ grep std_pip_args */package.py
cmor/package.py:            args = std_pip_args + ["--prefix=" + prefix, "."]
faiss/package.py:                args = std_pip_args + ["--prefix=" + prefix, "."]
fenics/package.py:                args = std_pip_args + ["--prefix=" + self.prefix, "."]
flatbuffers/package.py:                args = std_pip_args + ["--prefix=" + self.prefix, "."]
jsonnet/package.py:            args = std_pip_args + ["--prefix=" + self.prefix, "."]
mxnet/package.py:                args = std_pip_args + ["--prefix=" + prefix, "."]
py-dgl/package.py:            args = std_pip_args + ["--prefix=" + prefix, "."]
py-jaxlib/package.py:            args = std_pip_args + ["--prefix=" + self.prefix, "."]
py-keras/package.py:            args = std_pip_args + ["--prefix=" + prefix, "."]
py-or-tools/package.py:            args = std_pip_args + ["--prefix=" + prefix, "."]
py-pip/package.py:        args = [os.path.join(whl, "pip")] + std_pip_args + ["--prefix=" + prefix, whl]
py-setuptools/package.py:        args = ["-m", "pip"] + std_pip_args + ["--prefix=" + prefix, whl]
py-tensorboard-data-server/package.py:        args = std_pip_args + ["--prefix=" + prefix, wheel]
py-tensorflow-estimator/package.py:            args = std_pip_args + ["--prefix=" + prefix, "."]
py-tensorflow-hub/package.py:            args = std_pip_args + ["--prefix=" + prefix, "."]
py-tensorflow-probability/package.py:            args = std_pip_args + ["--prefix=" + prefix, "."]
py-tensorflow/package.py:            args = std_pip_args + ["--prefix=" + prefix, "."]
py-tfdlpack/package.py:            args = std_pip_args + ["--prefix=" + prefix, "."]
py-wheel/package.py:        args = std_pip_args + ["--prefix=" + prefix, self.stage.archive_file]
sgpp/package.py:            args = std_pip_args + ["--prefix=" + self.prefix, "."]
treelite/package.py:                args = std_pip_args + ["--prefix=" + self.prefix, "."]

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If these all have the same structure, should we make PythonManual (could use a better name) a new build system?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oof... some of these are much worse, Cmor is an autotools package that uses pip to install a module into its prefix, neither solution actually works for that without doing a view-like traversal.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Curious what @alalazo thinks. We could extend both the current base class and PythonPackage and have this be a separate function that can be called in each package.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, could do that. Could make it part of an Executable wrapper: pip_install say so that the command includes it? Even make it part of the existing callable pip from setup_dependent_packages?

@adamjstewart
Copy link
Copy Markdown
Member

@pradyunsg this is going to be a bit intrusive since we need to do this in dozens of places. Was this always the case with pip or is this bug only present in newer versions of pip? We could instead patch pip to restore the previous behavior if this is new.

@adamjstewart
Copy link
Copy Markdown
Member

I'm going to close this. It won't work unless we do it in the base class and literally every package that invokes pip directly. I think the fix should either be on pip's side or on the side of the Debian/RHEL developers who broke things in the first place.

@alalazo alalazo deleted the packages/py-docutils-bug branch May 12, 2023 15:24
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

build-systems core PR affects Spack core functionality python update-package

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants