conda / conda-libmamba-solver

The libmamba based solver for conda.
https://conda.github.io/conda-libmamba-solver/
Other
193 stars 23 forks source link

`noarch: python` packages do not install in `site-packages` if `python` is not a `run` requirement #497

Open sdebionne opened 2 months ago

sdebionne commented 2 months ago

Checklist

What happened?

We have packages that are actually plugins of another package. Up to conda < 24, installing the main project and the plugin worked fine. With conda >=24, we have the feeling that there is a race condition and that the plugin folder get recreated/overwritten by the main project

With two package containing:

Running conda install project project-bar-plugin reports not error but the site-packages/project/plugins/ does not contains bar.py.

I'll attach a repro ASAP.

Conda Info

active environment : test
    active env location : /home/debionne/miniconda3/envs/test
            shell level : 2
       user config file : /home/debionne/.condarc
 populated config files : /home/debionne/.condarc
          conda version : 24.4.0
    conda-build version : not installed
         python version : 3.10.8.final.0
                 solver : libmamba (default)
       virtual packages : __archspec=1=broadwell
                          __conda=24.4.0=0
                          __glibc=2.28=0
                          __linux=4.4.0=0
                          __unix=0=0
       base environment : /home/debionne/miniconda3  (writable)
      conda av data dir : /home/debionne/miniconda3/etc/conda
  conda av metadata url : None
           channel URLs : https://conda.anaconda.org/conda-forge/linux-64
                          https://conda.anaconda.org/conda-forge/noarch
          package cache : /home/debionne/miniconda3/pkgs
                          /home/debionne/.conda/pkgs
       envs directories : /home/debionne/miniconda3/envs
                          /home/debionne/.conda/envs
               platform : linux-64
             user-agent : conda/24.4.0 requests/2.28.1 CPython/3.10.8 Linux/4.4.0-19041-Microsoft debian/10.3 glibc/2.28 solver/libmamba conda-libmamba-solver/23.12.0 libmambapy/1.5.8
                UID:GID : 1000:1000
             netrc file : None
           offline mode : False

Conda Config

==> /home/debionne/.condarc <==
channels:
  - conda-forge

Conda list

# packages in environment at /home/debionne/miniconda3:
#
# Name                    Version                   Build  Channel
_libgcc_mutex             0.1                 conda_forge    conda-forge
_openmp_mutex             4.5                       2_gnu    conda-forge
archspec                  0.2.3              pyhd8ed1ab_0    conda-forge
asttokens                 2.1.0              pyhd8ed1ab_0    conda-forge
backcall                  0.2.0              pyh9f0ad1d_0    conda-forge
backports                 1.0                pyhd8ed1ab_3    conda-forge
backports.functools_lru_cache 1.6.4              pyhd8ed1ab_0    conda-forge
bash-completion           2.11                 ha770c72_1    conda-forge
boltons                   23.0.0             pyhd8ed1ab_0    conda-forge
brotlipy                  0.7.0           py310h5764c6d_1005    conda-forge
bzip2                     1.0.8                h7f98852_4    conda-forge
c-ares                    1.25.0               hd590300_0    conda-forge
ca-certificates           2024.6.2             hbcca054_0    conda-forge
certifi                   2024.6.2           pyhd8ed1ab_0    conda-forge
cffi                      1.15.1          py310h255011f_2    conda-forge
charset-normalizer        2.1.1              pyhd8ed1ab_0    conda-forge
colorama                  0.4.6              pyhd8ed1ab_0    conda-forge
conda                     24.4.0          py310hff52083_0    conda-forge
conda-bash-completion     1.5                           1    tartansandal
conda-libmamba-solver     23.12.0            pyhd8ed1ab_0    conda-forge
conda-package-handling    2.2.0              pyh38be061_0    conda-forge
conda-package-streaming   0.9.0              pyhd8ed1ab_0    conda-forge
cryptography              38.0.3          py310h600f1e7_0    conda-forge
curl                      8.7.1                hca28451_0    conda-forge
decorator                 5.1.1              pyhd8ed1ab_0    conda-forge
distro                    1.9.0              pyhd8ed1ab_0    conda-forge
doxygen                   1.9.5                h583eb01_0    conda-forge
executing                 1.2.0              pyhd8ed1ab_0    conda-forge
expat                     2.5.0                h27087fc_0    conda-forge
fmt                       10.2.1               h00ab1b0_0    conda-forge
gettext                   0.21.1               h27087fc_0    conda-forge
git                       2.39.2          pl5321h693f4a3_0    conda-forge
icu                       73.2                 h59595ed_0    conda-forge
idna                      3.4                pyhd8ed1ab_0    conda-forge
ipython                   8.6.0              pyh41d4057_1    conda-forge
jedi                      0.18.2             pyhd8ed1ab_0    conda-forge
jsonpatch                 1.32               pyhd8ed1ab_0    conda-forge
jsonpointer               2.0                        py_0    conda-forge
keyutils                  1.6.1                h166bdaf_0    conda-forge
krb5                      1.21.2               h659d440_0    conda-forge
ld_impl_linux-64          2.39                 hcc3a1bd_1    conda-forge
libarchive                3.7.2                h039dbb9_0    conda-forge
libcurl                   8.7.1                hca28451_0    conda-forge
libedit                   3.1.20191231         he28a2e2_2    conda-forge
libev                     4.33                 h516909a_1    conda-forge
libffi                    3.4.2                h7f98852_5    conda-forge
libgcc-ng                 12.2.0              h65d4601_19    conda-forge
libgomp                   12.2.0              h65d4601_19    conda-forge
libiconv                  1.17                 h166bdaf_0    conda-forge
libmamba                  1.5.8                had39da4_0    conda-forge
libmambapy                1.5.8           py310h39ff949_0    conda-forge
libnghttp2                1.58.0               h47da74e_1    conda-forge
libnsl                    2.0.0                h7f98852_0    conda-forge
libsolv                   0.7.24               hfc55251_4    conda-forge
libsqlite                 3.40.0               h753d276_0    conda-forge
libssh2                   1.11.0               h0841786_0    conda-forge
libstdcxx-ng              12.2.0              h46fd767_19    conda-forge
libuuid                   2.32.1            h7f98852_1000    conda-forge
libxml2                   2.11.5               h232c23b_1    conda-forge
libzlib                   1.2.13               h166bdaf_4    conda-forge
lz4-c                     1.9.3                h9c3ff4c_1    conda-forge
lzo                       2.10              h516909a_1000    conda-forge
mamba                     1.5.8           py310h51d5547_0    conda-forge
matplotlib-inline         0.1.6              pyhd8ed1ab_0    conda-forge
menuinst                  2.0.2           py310hff52083_0    conda-forge
ncurses                   6.3                  h27087fc_1    conda-forge
openssl                   3.3.1                h4ab18f5_1    conda-forge
packaging                 23.1               pyhd8ed1ab_0    conda-forge
parso                     0.8.3              pyhd8ed1ab_0    conda-forge
pcre2                     10.40                hc3806b6_0    conda-forge
perl                      5.32.1          2_h7f98852_perl5    conda-forge
pexpect                   4.8.0              pyh1a96a4e_2    conda-forge
pickleshare               0.7.5                   py_1003    conda-forge
pip                       22.3.1             pyhd8ed1ab_0    conda-forge
platformdirs              4.1.0              pyhd8ed1ab_0    conda-forge
pluggy                    1.0.0              pyhd8ed1ab_5    conda-forge
ply                       3.11                       py_1    conda-forge
prompt-toolkit            3.0.33             pyha770c72_0    conda-forge
prompt_toolkit            3.0.33               hd8ed1ab_0    conda-forge
ptyprocess                0.7.0              pyhd3deb0d_0    conda-forge
pure_eval                 0.2.2              pyhd8ed1ab_0    conda-forge
pybind11-abi              4                    hd8ed1ab_3    conda-forge
pycosat                   0.6.4           py310h5764c6d_1    conda-forge
pycparser                 2.21               pyhd8ed1ab_0    conda-forge
pygments                  2.13.0             pyhd8ed1ab_0    conda-forge
pyopenssl                 22.1.0             pyhd8ed1ab_0    conda-forge
pyparsing                 3.0.9              pyhd8ed1ab_0    conda-forge
pysocks                   1.7.1              pyha2e5f31_6    conda-forge
python                    3.10.8          h4a9ceb5_0_cpython    conda-forge
python_abi                3.10                    3_cp310    conda-forge
readline                  8.1.2                h0f457ee_0    conda-forge
reproc                    14.2.3               h7f98852_0    conda-forge
reproc-cpp                14.2.3               h9c3ff4c_0    conda-forge
requests                  2.28.1             pyhd8ed1ab_1    conda-forge
ruamel.yaml               0.17.21         py310h5764c6d_2    conda-forge
ruamel.yaml.clib          0.2.7           py310h1fa729e_1    conda-forge
ruamel_yaml               0.15.80         py310h5764c6d_1008    conda-forge
setuptools                65.5.1             pyhd8ed1ab_0    conda-forge
sip                       6.7.5           py310hd8f1fbe_0    conda-forge
six                       1.16.0             pyh6c4a22f_0    conda-forge
sqlite                    3.40.0               h4ff8645_0    conda-forge
stack_data                0.6.1              pyhd8ed1ab_0    conda-forge
tk                        8.6.12               h27826a3_0    conda-forge
toml                      0.10.2             pyhd8ed1ab_0    conda-forge
toolz                     0.12.0             pyhd8ed1ab_0    conda-forge
tqdm                      4.64.1             pyhd8ed1ab_0    conda-forge
traitlets                 5.5.0              pyhd8ed1ab_0    conda-forge
truststore                0.8.0              pyhd8ed1ab_0    conda-forge
tzdata                    2022f                h191b570_0    conda-forge
urllib3                   1.26.13            pyhd8ed1ab_0    conda-forge
wcwidth                   0.2.5              pyh9f0ad1d_2    conda-forge
wheel                     0.38.4             pyhd8ed1ab_0    conda-forge
xz                        5.2.6                h166bdaf_0    conda-forge
yaml                      0.2.5                h7f98852_2    conda-forge
yaml-cpp                  0.8.0                h59595ed_0    conda-forge
zstandard                 0.21.0          py310h1275a96_1    conda-forge
zstd                      1.5.5                hfc55251_0    conda-forge

Additional Context

No response

sdebionne commented 2 months ago

Here is the repro that I had in mind, but unfortunately it does not repro. The real project that shows the issue depends on many third party dependencies so the dynamic of the installation is different.

conda-bug-14012.tar.gz

sdebionne commented 2 months ago

Since I cannot provide a repro easily (but it still shows the structure of the project), I can provide a real world repro:

$ conda --version
conda 23.11.0
$ conda create -n test lima-camera-simulator-tango
...
$  ll $CONDA_PREFIX/lib/python3.10/site-packages/Lima/Server/camera
total 32
-rw-rw-r-- 2 Jul  1 08:42 __init__.py
-rw-rw-r-- 2 Oct 19  2022 Simulator.py <------ PLUGIN OK
$ conda --version
conda 24.4.0
$ conda create -n test lima-camera-simulator-tango
...
$  ll $CONDA_PREFIX/lib/python3.10/site-packages/Lima/Server/camera
total 32
-rw-rw-r-- 2 1676 Jul  1 08:42 __init__.py
                               <------ MISSING PLUGIN

Environments are identicals with both versions of Conda.

sdebionne commented 2 months ago

Investigating further, with Conda >= 24, the plugin file (here Simulator.py) is actually installed in the wrong folder:

$CONDA_PREFIX/site-packages/Lima/Server/camera/Simulator.py

while it should be

$CONDA_PREFIX/lib/python3.10/site-packages/Lima/Server/camera/Simulator.py

e.g. the site-packages folder is not properly prefixed.

travishathaway commented 2 months ago

@sdebionne,

Is there anyway you could link to the project you are having difficulties with? This would help us debug what is currently happening.

From what I have read so far, I think that this is less of a problem with conda and more of a problem with the way this program is being packaged. For example, it's bad practice for one package to modify the contents of another like this. Each individual package, even if they are plugins, should be contained to themselves.

The reason for this is that it helps ensure package integrity. This can be important for security reasons because you would want to know when a package has been tampered with. For example, after adding new files to a package, the checksum value of the package at the time it was built would no longer match.

Regardless, it would really help to see the recipes for these packages to see exactly what's going on.

sdebionne commented 2 months ago

Thank you for your feedback @travishathaway,

You are right, we should improve our plugin discovery mechanism, so that plugin should not need to be installed in the tree of the main project. In the other hand there is clearly a change of behavior from conda 23 to 24, where our packages stopped to install properly.

While investigating, I found out that the same package does not install the same way with conda 24: it misses the site-packages prefix so that site-packages get copied directly in $CONDA_PREFIX and not in lib\python<version>

While trying to find a workaround, I noticed that switching from a CMake install (that would basically copy a single python file to the proper folder in site-packages) to a pip/setuptools install, fixed the issue. The main difference I see is a direct (build) dependency to python but maybe setuptools generates metadata that are now mandatory to get a "true" noarch python package.

The old package was plugin-project-1.10.0-0.tar.bz2 while the new one is (mind the py) plugin-project-1.10.0-py_1.tar.bz2. So I wonder if, while both recipes use noarch: python, the one without python as direct dependency, did not actually build correctly.

sdebionne commented 2 months ago

The plugin project and recipe is in https://github.com/esrf-bliss/Lima-camera-simulator/blob/develop/conda/tango , but I am afraid it is a bit "opaque"...

travishathaway commented 2 months ago

Thanks for the link to your project.

At this point, I am open to the possibility that a regression may have been introduced in the 24.1.0 release. But, considering that you have found a work around, I will not make this issue a priority.

One change that could come out of this though is to improve the conda-build documentation to warn against the method you were initially using.

Let's leave this discussion open though in case others in the community are facing similar issues.

jaimergp commented 1 month ago

Looking at the recipe, you definitely need python in that meta.yaml requirements. It's good practice to be explicit about the direct dependencies. I'd add a host section with python and pip (and lower bounds >=x.y as required by your project), and also add python >=x.y to run.

Shared namespace packages are supported and you can see some examples by examining the backports family, but that CMake config is maybe a bit non standard to follow the assumptions conda-build makes to support them?

jaimergp commented 1 month ago

Do you have a link to the artifacts themselves? Maybe there's something wrong with their "noarchness", because the plugin is being extracted its "noarch path" (starts with site-packages) instead of the "expanded path" (lib/pythonx.y/site-packages).

sdebionne commented 1 month ago

Sorry for the late answer, here is a link to the artifacts. I am trying to add the python as direct dependency to check whether that helps with the "noarch-pythoness".

jaimergp commented 1 month ago

I took a look and these are my findings. I can't reproduce your issue with latest conda.

This is what I did, assuming the artifacts have been downloaded to a local lima-channel directory.

$ conda create -n lima python=3.10 --platform=linux-64
$ conda activate lima
$ conda install lima-channel/linux-64/lima-camera-simulator-1.10.0-py310h2bc3f7f_0.tar.bz2 lima-channel/noarch/lima-camera-simulator-tango-1.10.0-0.tar.bz2 
$ tree $CONDA_PREFIX/lib/python3.10/site-packages/Lima/
/opt/conda/envs/lima/lib/python3.10/site-packages/Lima/
├── Server
│   └── camera
│       └── Simulator.py  # <------- this is the file we are after, right?
└── Simulator
    ├── Simulator.py
    ├── __init__.py
    └── __pycache__
        ├── Simulator.cpython-310.pyc
        └── __init__.cpython-310.pyc

4 directories, 5 files
sdebionne commented 1 month ago

This looks good indeed. With the same artifact uploaded on Anaconda, why would I get a different results:

$ conda --version
conda 24.4.0
$ conda create -n lima-tmp
$ conda activate lima-tmp
$ conda install -c esrf-bcu lima-camera-simulator-tango=1.10.0=0
$ tree $CONDA_PREFIX/lib/python3.10/site-packages/Lima/    # edited output for better readability
/miniconda3/envs/lima-tmp/lib/python3.10/site-packages/Lima
├── Server
│   ├── camera
│   │   ├── __init__.py   # <------- file is missing
│   │   └── __pycache__
│   │       └── __init__.cpython-310.pyc

$ tree $CONDA_PREFIX/site-packages/
/miniconda3/envs/lima-tmp/site-packages/
└── Lima
    └── Server
        └── camera
            ├── __pycache__
            │   └── Simulator.cpython-310.pyc
            └── Simulator.py    # <------- found it but not in expended path

I intentionally did not install python in the env as it is an (indirect) dependency of the package.

sdebionne commented 1 month ago

Same result with conda 24.5.0

jaimergp commented 1 month ago

Yes, I understand why now.

The direct path/URL works because the solver doesn't have to be involved and conda parses the internal JSON metadata directly, which correctly points out that it's noarch: python.

With conda-libmamba-solver and libmamba v1, we lose the noarch information on they way out from the solver, and have to infer it from the subdir. But there are two types of noarch: python and generic. We rely on python being present in the run dependencies (as it should) to identify noarch: python. But since your package doesn't have it, it misses that, and considers it generic. See code here.

This won't be a problem with libmamba v2, because we do get the full noarch information without having to infer anything, but for now we need to be a bit more strict with the run requirements.

Sorry it took so long for me to realize it was about that!

sdebionne commented 1 month ago

Sorry it took so long for me to realize it was about that!

Awesome support, thank you!

jaimergp commented 1 month ago

I'll move this to conda-libmamba-solver because it's a "bug" there, not in conda. --solver=classic should work, btw.