relenv icon indicating copy to clipboard operation
relenv copied to clipboard

relenv breaks pip install

Open smarsching opened this issue 1 year ago • 0 comments

Recent versions of relenv (at least 0.15.0, 0.15.1, and 0.16.0) break pip install when used with the --target argument.

This causes salt-pip not to work correctly when trying to install some Python modules like mysqlclient (saltstack/salt#65980) or M2Crypto (saltstack/salt#66311).

I can definitely track this down to an issue in relenv because the problem can be resolved by commenting removing a single line in relenv’s runtime.py:

--- relenv/runtime.py.orig	2024-05-17 14:49:35.522975150 +0000
+++ relenv/runtime.py	2024-05-17 14:51:00.735990855 +0000
@@ -783,7 +783,6 @@
         Wrapper("pip._internal.operations.install.wheel", wrap_pip_install_wheel),
         Wrapper("pip._internal.operations.install.legacy", wrap_pip_install_legacy),
         Wrapper("pip._internal.operations.build.wheel", wrap_pip_build_wheel),
-        Wrapper("pip._internal.commands.install", wrap_cmd_install),
         Wrapper("pip._internal.locations", wrap_locations),
         Wrapper("pip._internal.cli.req_command", wrap_req_command),
         Wrapper("pip._internal.req.req_install", wrap_req_install),

As this might have undesired side effects (I do not understand the code well enough to be sure): I also tried more localized changes and came up with the following patch that resolves the issue:

--- relenv/runtime.py.orig	2024-05-17 14:49:35.522975150 +0000
+++ relenv/runtime.py	2024-05-17 14:53:50.545215677 +0000
@@ -641,19 +641,6 @@
 
     mod.InstallCommand.run = wrap(mod.InstallCommand.run)
 
-    def wrap(func):
-        @functools.wraps(func)
-        def wrapper(self, target_dir, target_temp_dir, upgrade):
-            from pip._internal.cli.status_codes import SUCCESS
-
-            return SUCCESS
-
-        return wrapper
-
-    if hasattr(mod.InstallCommand, "_handle_target_dir"):
-        mod.InstallCommand._handle_target_dir = wrap(
-            mod.InstallCommand._handle_target_dir
-        )
     return mod
 
 
@@ -670,8 +657,6 @@
         ):
             scheme = func(dist_name, user, home, root, isolated, prefix)
             if TARGET.TARGET:
-                scheme.platlib = TARGET.PATH
-                scheme.purelib = TARGET.PATH
                 scheme.data = TARGET.PATH
             return scheme
 
@@ -729,8 +714,6 @@
                 use_user_site=False,
                 pycompile=True,
             ):
-                if TARGET.TARGET:
-                    home = TARGET.PATH
                 return func(
                     self,
                     install_options,
@@ -756,8 +739,6 @@
                 use_user_site=False,
                 pycompile=True,
             ):
-                if TARGET.TARGET:
-                    home = TARGET.PATH
                 return func(
                     self,
                     global_options,

In order to resolve the error when trying to install the module, the change that avoids setting scheme.platlib and scheme.purelib is sufficient, but when only applying this change and not the other changes, the installed modules end up in /opt/saltstack/salt/extras-3.10/lib/python instead of /opt/saltstack/salt/extras-3.10.

When applying the change regarding scheme.purelib and home = TARGET.PATH, but not removing the wrapper for _handle_target_dir, there is no error but the module is not installed at all.

If I understand it correctly, home is usually set to a temporary directory and _handle_target_dir copies it from there to the actual target path. This is why not overriding home but replacing _handle_target_dir results in the module not being installed at all (it ends up in the temporary directory and is never moded from there).

@dwoz Unfortunately, I do not understand the intention behind this code, so I am not sure whether my fix is correct or might break something else. As it seems like you wrote most of this code, I hope that you might be able to explain what this code is supposed to do.

Maybe this code was targeted at an older version of pip, and due to changes in pip, it does not work correctly any longer (after all, the code messes with internals of pip). I tested my patch with Salt 3006.8, which bundles pip 23.3.2.

Some of the commits that added the code that is removed by my patch say something about fixing pip uninstall, but at fore the aforementioned version of pip, uninstall still works correctly after applying my patch.

smarsching avatar May 17 '24 15:05 smarsching