rez icon indicating copy to clipboard operation
rez copied to clipboard

Make rez wheels production ready

Open JeanChristopheMorinPerso opened this issue 2 years ago • 7 comments

Make rez fully installable with pip, even for production uses. This takes some of the ideas in https://github.com/AcademySoftwareFoundation/rez/pull/1039 by @davidlatwe and improves them to make the whole concept work.

Included in the PR:

  • Fully working pip installable wheels for production use.
  • A forked and slightly modified simple launcher. The license is BSD-2.
  • No more .rez_production_install.
  • Completely removed the notion of production install from the code base.
  • Integration tests that demonstrate that it really works (see the wheel.yaml workflow).

TODO:

  • [ ] Implement the release of the new wheels.
  • [ ] Include all this text into the docs, or at least in a README somewhere.
  • [x] Should this somehow be feature flagged? Right now the install script will use all the new stuff...
    • Changes have been made to make the install script use the old method.

What is a production install today?

Our install.py script does mainly three things, out of which two are to guarantee that rez will work in a production environment:

  1. Create a virtualenv and install rez into it (using pip install .).
  2. It copies all the commands (console entrypoints) from the virtualenv's "bin" folder into the "bin/rez" folder. This is necessary because we want to be able to add the commands to $PATH but we don't want the python executable from the virtualenv to be on PATH. We also can't remove the python executable from the bin folder because that would make it impossible to install rez plugins.
  3. All scripts (commands) have their shebang modified from #!/path/to/rez/venv/bin/python to #!/path/to/rez/venv/bin/python -E (we add -E) and we generate custom .exes on Windows to do the same thing. -E is important for us because we don't want PYTHONPATH to affect the rez commands.

The goal of all this is to insulate the rez install from everything. Nothing should affect it. It must work under all conditions. Additionally, rez must not be affected by a rez environment. For example, if your rez install uses Python 3.7 and you rez-env python-3.12, running rez commands inside that new environment must use the Python 3.7 interpreter from the rez install! Rez must also ignore any environment variables that could affect it (PYTHONPATH, etc).

The install script is needed today because the Python ecosystem was not designed with these goals in mind. When you install a package with pip (or any other installer) and that package has commands (console entry points), installers will create small script wrappers that look like this:

#!/home/jcmorin/jcmenv/aswf/rez/.venv/bin/python3
# -*- coding: utf-8 -*-
import re
import sys
from pytest import console_main
if __name__ == '__main__':
    sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0])
    sys.exit(console_main())

As you can see, it doesn't have the -E flag in the shebang. And most importantly, there is no way to tell installers to use a custom shebang or where the scripts will be installed. They always go in bin (macOS, Linux) or Scripts (Windows).

The install.py script exists to fix all this. It was created because it was the easiest thing to do.

Why is it a problem to have to run the install.py script?

Python users are used to simply install things with their preferred installer (pip, etc). So it is natural that they would also want to decide how they want to install rez.

But with what we've seen above, they can't. Or more, they can but they'll see warnings every time they use the CLI.

We get asked quite often why can't they simply pip install rez.

It's very annoying to have to clone a repo and have to run a script. The alternative is to download an archive from a release and unpack it and run the install script. Both options are annoying IMO, and I'm not the only one annoyed by this based on all the discussions we've had on that subject in the last couple of years.

How do we fix this?

This PR utilizes the .data directory of the wheel format. The .data can contain a couple of folders, one of which is the scripts folder. The scripts folder is understood and supported by installers. Anything in scripts will go in <prefix>/bin (macOS, Linux) or <prefix>/Scripts (Windows) as is (or almost as is).

So what we do is generate the console scripts at build time and store them inside rez-<version>.data/scripts/rez in the wheel. When pip installs the wheel, it will unpack everything from <dist>-<version>.data/scripts into the bin folder and it will respect the hierarchy defined in the wheel! Pip will also replace the interpreter path found in the script's shebang with the venv's one. Again this is important because we want rez to use its own Python. So that's one problem solved (point 2 from above).

Example of what is inside the wheel
      649  2024-05-11 20:21   rez-3.1.1.data/scripts/rez/_rez-complete
      657  2024-05-11 20:21   rez-3.1.1.data/scripts/rez/_rez-install-test
      639  2024-05-11 20:21   rez-3.1.1.data/scripts/rez/_rez_fwd
      631  2024-05-11 20:21   rez-3.1.1.data/scripts/rez/rez
      651  2024-05-11 20:21   rez-3.1.1.data/scripts/rez/rez-benchmark
      641  2024-05-11 20:21   rez-3.1.1.data/scripts/rez/rez-bind
      643  2024-05-11 20:21   rez-3.1.1.data/scripts/rez/rez-build
      645  2024-05-11 20:21   rez-3.1.1.data/scripts/rez/rez-bundle
      645  2024-05-11 20:21   rez-3.1.1.data/scripts/rez/rez-config
      647  2024-05-11 20:21   rez-3.1.1.data/scripts/rez/rez-context
      637  2024-05-11 20:21   rez-3.1.1.data/scripts/rez/rez-cp
      647  2024-05-11 20:21   rez-3.1.1.data/scripts/rez/rez-depends
      641  2024-05-11 20:21   rez-3.1.1.data/scripts/rez/rez-diff
      639  2024-05-11 20:21   rez-3.1.1.data/scripts/rez/rez-env
      639  2024-05-11 20:21   rez-3.1.1.data/scripts/rez/rez-gui
      641  2024-05-11 20:21   rez-3.1.1.data/scripts/rez/rez-help
      651  2024-05-11 20:21   rez-3.1.1.data/scripts/rez/rez-interpret
      649  2024-05-11 20:21   rez-3.1.1.data/scripts/rez/rez-memcache
      637  2024-05-11 20:21   rez-3.1.1.data/scripts/rez/rez-mv
      639  2024-05-11 20:21   rez-3.1.1.data/scripts/rez/rez-pip
      651  2024-05-11 20:21   rez-3.1.1.data/scripts/rez/rez-pkg-cache
      653  2024-05-11 20:21   rez-3.1.1.data/scripts/rez/rez-pkg-ignore
      647  2024-05-11 20:21   rez-3.1.1.data/scripts/rez/rez-plugins
      645  2024-05-11 20:21   rez-3.1.1.data/scripts/rez/rez-python
      647  2024-05-11 20:21   rez-3.1.1.data/scripts/rez/rez-release
      637  2024-05-11 20:21   rez-3.1.1.data/scripts/rez/rez-rm
      645  2024-05-11 20:21   rez-3.1.1.data/scripts/rez/rez-search
      649  2024-05-11 20:21   rez-3.1.1.data/scripts/rez/rez-selftest
      645  2024-05-11 20:21   rez-3.1.1.data/scripts/rez/rez-status
      643  2024-05-11 20:21   rez-3.1.1.data/scripts/rez/rez-suite
      641  2024-05-11 20:21   rez-3.1.1.data/scripts/rez/rez-test
      641  2024-05-11 20:21   rez-3.1.1.data/scripts/rez/rez-view
      647  2024-05-11 20:21   rez-3.1.1.data/scripts/rez/rez-yaml2py
      639  2024-05-11 20:21   rez-3.1.1.data/scripts/rez/rezolve

Now, how do we solve the fact that we can't easily add -E to the shebang? This is solved with this little trick in our custom console scripts:

#!/usr/bin/python
# -*- coding: utf-8 -*-
import os
import re
import sys
import platform

# If -E is not passed, then inject it and re-execute ourselves.
# Note that this is not done on Windows because the Windows launcher
# already does this.
if not sys.flags.ignore_environment and platform.system() != 'Windows':
    args = [sys.executable, '-E'] + sys.argv
    if os.getenv('REZ_LAUNCHER_DEBUG'):
        print('Launching:', ' '.join(args))

    # Re-execute ourself, this time with the -E flag.
    os.execvp(sys.executable, args)


from rez.cli._entry_points import run_rez_build
if __name__ == '__main__':
    sys.argv[0] = re.sub(r'(-script\\.pyw|\\.exe)?$', '', sys.argv[0])
    sys.exit(run_rez_build())

This is the rez-build script that we store in our wheel. Note that pip will automatically replace /usr/bin/python by <absolute path to venv>/bin/python at install time.

Because we want to let pip bake the absolute path to the interpreter at install time, we can't pass any custom flags in there. If we were to specify #!/usr/bin/python -E, pip would not replace the path with the path we want.

So what we do is to check how the script was executed. It's possible to know if Python was started with -E or not by querying sys.flags.ignore_environment. If it was not started with -E, we re-exec ourselves with -E prepended to the arguments.

At least that's on Linux. On Windows, things are more complicated (as usual).

On Windows, we need executables to be able to just run "rez" or "rez-env", etc. Why? Because on Windows, you can't execute a random file without an extension. So you have to wrap the little Python script above with an executable. Pip usually takes care of that with entry points, but it doesn't do so for scripts, by design.

These executables are called "launchers" in the Python ecosystems. CPython has a built-in one, then there is the original simple launcher by Vinay Sajip and there is also a derivative of the simple launcher in distlib also by Vinay Sajip. There is a fourth one in setuptools, but let's ignore this one. Pip uses the one from distlib.

What I did was to take the one from distlib and put it into the launchers folder. I then patched it to fit our needs. The patch is small:

Diff
diff --git a/tmp/asd/launcher.c b/./launcher.c
index 727f7916..8265a2bb 100644
--- a/tmp/asd/launcher.c
+++ b/./launcher.c
@@ -23,6 +23,8 @@
  * POSSIBILITY OF SUCH DAMAGE.
  */
 
+// This file is taken from https://github.com/pypa/distlib/blob/0.3.7/PC/launcher.c.
+// You can diff the files to see the changes.
 #ifndef _WIN32_WINNT            // Specifies that the minimum required platform is Windows Vista.
 #define _WIN32_WINNT 0x0600     // Change this to the appropriate value to target other versions of Windows.
 #endif
@@ -31,13 +33,9 @@
 #include <io.h>
 #include <stdlib.h>
 #include <windows.h>
-#include <Shlwapi.h>
+#include <shlwapi.h>
 
-#pragma comment (lib, "Shlwapi.lib")
-
-#define APPENDED_ARCHIVE
-#define USE_ENVIRONMENT
-#define SUPPORT_RELATIVE_PATH
+#pragma comment (lib, "shlwapi.lib")
 
 #define MSGSIZE 1024
 
@@ -822,6 +820,13 @@ run_child(wchar_t * cmdline)
 #endif
         si.dwFlags |= STARTF_USESTDHANDLES;
     }
+
+    size_t rez_envvar_size = 0;
+    getenv_s(&rez_envvar_size, NULL, 0, "REZ_LAUNCHER_DEBUG");
+    if (rez_envvar_size > 0) {
+        printf("Launching: %ls\n", cmdline);
+    }
+
     ok = CreateProcessW(NULL, cmdline, NULL, NULL, TRUE, 0, NULL, NULL, &si, &child_process_info);
     if (!ok) {
         // Failed to create process. See if we can find out why.
@@ -1027,11 +1032,12 @@ process(int argc, char * argv[])
         wcp = pbuffer;
     }
 #endif
-     /* 3 spaces + 4 quotes + NUL */
-    len = wcslen(wcp) + wcslen(wp) + 8 + wcslen(psp) + wcslen(cmdline);
+     /* 4 spaces + 4 quotes + -E + NUL */
+    len = wcslen(wcp) + wcslen(wp) + 11 + wcslen(psp) + wcslen(cmdline);
     cmdp = (wchar_t *) calloc(len, sizeof(wchar_t));
     assert(cmdp != NULL, "Expected to be able to allocate command line memory");
-    _snwprintf_s(cmdp, len, len, L"\"%ls\" %ls \"%ls\" %ls", wcp, wp, psp, cmdline);
+    // Note that we inject -E to make sure PYTHON* variables are not picked up.
+    _snwprintf_s(cmdp, len, len, L"\"%ls\" -E %ls \"%ls\" %ls", wcp, wp, psp, cmdline);
     run_child(cmdp);  /* never actually returns */
     free(cmdp);
     return 0;

We basically

  • Remove the APPENDED_ARCHIVE preprocessor directive so that the console script is not embedded in the EXE file.
  • Remove the USE_ENVIRONMENT preprocessor directive to not use any environment variables to resolve the path to python.
  • Remove the SUPPORT_RELATIVE_PATH preprocessor directive to make sure that the embedded python path doesn't use a relative path.
  • Add support for a new environment variable, REZ_LAUNCHER_DEBUG that will tell the launcher to print the full command line that will be used to start python (and run the console script).
  • Add -E to the arguments used when launching python.

We put the launchers in the wheel too. And this solves the last remaining problem we had.

Example of what is inside the wheel
      649  2024-05-11 20:21   rez-3.1.1.data/scripts/rez/_rez-complete-script.py
      999  2024-05-11 20:21   rez-3.1.1.data/scripts/rez/_rez-complete.exe
      657  2024-05-11 20:21   rez-3.1.1.data/scripts/rez/_rez-install-test-script.py
      999  2024-05-11 20:21   rez-3.1.1.data/scripts/rez/_rez-install-test.exe
      639  2024-05-11 20:21   rez-3.1.1.data/scripts/rez/_rez_fwd-script.py
      999  2024-05-11 20:21   rez-3.1.1.data/scripts/rez/_rez_fwd.exe
      631  2024-05-11 20:21   rez-3.1.1.data/scripts/rez/rez-script.py
      999  2024-05-11 20:21   rez-3.1.1.data/scripts/rez/rez.exe
      651  2024-05-11 20:21   rez-3.1.1.data/scripts/rez/rez-benchmark-script.py
      999  2024-05-11 20:21   rez-3.1.1.data/scripts/rez/rez-benchmark.exe
      641  2024-05-11 20:21   rez-3.1.1.data/scripts/rez/rez-bind-script.py
      999  2024-05-11 20:21   rez-3.1.1.data/scripts/rez/rez-bind.exe
      643  2024-05-11 20:21   rez-3.1.1.data/scripts/rez/rez-build-script.py
      999  2024-05-11 20:21   rez-3.1.1.data/scripts/rez/rez-build.exe
      645  2024-05-11 20:21   rez-3.1.1.data/scripts/rez/rez-bundle-script.py
      999  2024-05-11 20:21   rez-3.1.1.data/scripts/rez/rez-bundle.exe
      645  2024-05-11 20:21   rez-3.1.1.data/scripts/rez/rez-config-script.py
      999  2024-05-11 20:21   rez-3.1.1.data/scripts/rez/rez-config.exe
      647  2024-05-11 20:21   rez-3.1.1.data/scripts/rez/rez-context-script.py
      999  2024-05-11 20:21   rez-3.1.1.data/scripts/rez/rez-context.exe
      637  2024-05-11 20:21   rez-3.1.1.data/scripts/rez/rez-cp-script.py
      999  2024-05-11 20:21   rez-3.1.1.data/scripts/rez/rez-cp.exe
      647  2024-05-11 20:21   rez-3.1.1.data/scripts/rez/rez-depends-script.py
      999  2024-05-11 20:21   rez-3.1.1.data/scripts/rez/rez-depends.exe
      641  2024-05-11 20:21   rez-3.1.1.data/scripts/rez/rez-diff-script.py
      999  2024-05-11 20:21   rez-3.1.1.data/scripts/rez/rez-diff.exe
      639  2024-05-11 20:21   rez-3.1.1.data/scripts/rez/rez-env-script.py
      999  2024-05-11 20:21   rez-3.1.1.data/scripts/rez/rez-env.exe
      639  2024-05-11 20:21   rez-3.1.1.data/scripts/rez/rez-gui-script.pyw
      999  2024-05-11 20:21   rez-3.1.1.data/scripts/rez/rez-gui.exe
      641  2024-05-11 20:21   rez-3.1.1.data/scripts/rez/rez-help-script.py
      999  2024-05-11 20:21   rez-3.1.1.data/scripts/rez/rez-help.exe
      651  2024-05-11 20:21   rez-3.1.1.data/scripts/rez/rez-interpret-script.py
      999  2024-05-11 20:21   rez-3.1.1.data/scripts/rez/rez-interpret.exe
      649  2024-05-11 20:21   rez-3.1.1.data/scripts/rez/rez-memcache-script.py
      999  2024-05-11 20:21   rez-3.1.1.data/scripts/rez/rez-memcache.exe
      637  2024-05-11 20:21   rez-3.1.1.data/scripts/rez/rez-mv-script.py
      999  2024-05-11 20:21   rez-3.1.1.data/scripts/rez/rez-mv.exe
      639  2024-05-11 20:21   rez-3.1.1.data/scripts/rez/rez-pip-script.py
      999  2024-05-11 20:21   rez-3.1.1.data/scripts/rez/rez-pip.exe
      651  2024-05-11 20:21   rez-3.1.1.data/scripts/rez/rez-pkg-cache-script.py
      999  2024-05-11 20:21   rez-3.1.1.data/scripts/rez/rez-pkg-cache.exe
      653  2024-05-11 20:21   rez-3.1.1.data/scripts/rez/rez-pkg-ignore-script.py
      999  2024-05-11 20:21   rez-3.1.1.data/scripts/rez/rez-pkg-ignore.exe
      647  2024-05-11 20:21   rez-3.1.1.data/scripts/rez/rez-plugins-script.py
      999  2024-05-11 20:21   rez-3.1.1.data/scripts/rez/rez-plugins.exe
      645  2024-05-11 20:21   rez-3.1.1.data/scripts/rez/rez-python-script.py
      999  2024-05-11 20:21   rez-3.1.1.data/scripts/rez/rez-python.exe
      647  2024-05-11 20:21   rez-3.1.1.data/scripts/rez/rez-release-script.py
      999  2024-05-11 20:21   rez-3.1.1.data/scripts/rez/rez-release.exe
      637  2024-05-11 20:21   rez-3.1.1.data/scripts/rez/rez-rm-script.py
      999  2024-05-11 20:21   rez-3.1.1.data/scripts/rez/rez-rm.exe
      645  2024-05-11 20:21   rez-3.1.1.data/scripts/rez/rez-search-script.py
      999  2024-05-11 20:21   rez-3.1.1.data/scripts/rez/rez-search.exe
      649  2024-05-11 20:21   rez-3.1.1.data/scripts/rez/rez-selftest-script.py
      999  2024-05-11 20:21   rez-3.1.1.data/scripts/rez/rez-selftest.exe
      645  2024-05-11 20:21   rez-3.1.1.data/scripts/rez/rez-status-script.py
      999  2024-05-11 20:21   rez-3.1.1.data/scripts/rez/rez-status.exe
      643  2024-05-11 20:21   rez-3.1.1.data/scripts/rez/rez-suite-script.py
      999  2024-05-11 20:21   rez-3.1.1.data/scripts/rez/rez-suite.exe
      641  2024-05-11 20:21   rez-3.1.1.data/scripts/rez/rez-test-script.py
      999  2024-05-11 20:21   rez-3.1.1.data/scripts/rez/rez-test.exe
      641  2024-05-11 20:21   rez-3.1.1.data/scripts/rez/rez-view-script.py
      999  2024-05-11 20:21   rez-3.1.1.data/scripts/rez/rez-view.exe
      647  2024-05-11 20:21   rez-3.1.1.data/scripts/rez/rez-yaml2py-script.py
      999  2024-05-11 20:21   rez-3.1.1.data/scripts/rez/rez-yaml2py.exe
      639  2024-05-11 20:21   rez-3.1.1.data/scripts/rez/rezolve-script.py
      999  2024-05-11 20:21   rez-3.1.1.data/scripts/rez/rezolve.exe

The cool part is that the launchers are only compiled when building a wheel on Windows, and Visual Studio is not even needed! We use the awesome C/C++ compiler provided by the Zig language. Since it's available as an official package on PyPI (ziglang), everything just works.

That's it?

Yes, that's pretty much it. Or almost. We have to talk about wheels a little bit more. Because who doesn't like to talk about wheels?

There is a last detail to talk about and it's the final wheels. We will generate three of them:

  • A generic wheel (pure) that works on all platforms. It'll be called rez-<version>-py3-none-any.whl.
  • An amd64 wheel for Windows that will be called rez-<version>-py3-none-win_amd64.whl.
  • An arm64 wheel for Windows that will be called rez-<version>-py3-none-win_arm64.whl.

By generating a generic wheel for non-Windows platforms, pip will be able to install rez on everything that is not Windows (macOS, Linux, etc).

And because installers have to prefer more specific wheels before generic ones, they will install the Windows variants if installed on Windows.

@JeanChristopheMorinPerso , might this sort of workflow open the door for us to be able to have rez and rez plugins exist slightly closer together in a standard way? (Thought provoked by TSC meeting)

maxnbk avatar Sep 21 '23 20:09 maxnbk

@maxnbk I'm not sure how to answer this. Can you clarify what you mean by "open the door for us to be able to have rez and rez plugins exist slightly closer together in a standard way" please?

I think I finally got it working with -E. It took some more thinking outside the box, but it now works. See https://github.com/AcademySoftwareFoundation/rez/actions/runs/6278210700/job/17051519463?pr=1536#step:7:74 which proves it. This line comes from a custom command I added to rez, jctest that basically prints sys.flags. In our case, we are interested in sys.flags.ignore_environment which basically proves that -E was passed correctly.

I also adapted the PR so that it works on Linux and macOS too. For that, I had to modify the scripts we generate on unix to

#!/usr/bin/python
# -*- coding: utf-8 -*-
import os
import re
import sys
import platform
# If -E is not passed, then inject it and re-execute outself.
# Note that this is not done on Windows because the Windows launcher
# already does this.
if not sys.flags.ignore_environment and platform.system() != 'Windows':
    args = [sys.executable, '-E'] + sys.argv
    if os.getenv('REZ_LAUNCHER_DEBUG'):
        print('Launching:', ' '.join(args))
    os.execvp(sys.executable, args)
from rez.cli._entry_points import {0}
if __name__ == '__main__':
    sys.argv[0] = re.sub(r'(-script\\.pyw|\\.exe)?$', '', sys.argv[0])
    sys.exit({0}())

This is needed because pip doesn't keep the arguments in the shebang. On Windows, I simply inject -E from the launcher executable. I could have use the same method on unix and Windows, but I know launching processes on Windows is costly and it would have resulted in 3 processes started instead of 2.

Next step, clean up, write a proper workflow to generate the wheels on all platforms, figure out where to store the launcher and write at least one integration test that would do this:

  1. Install rez with Python version X (say 3.7).
  2. Create a Python 3.11 rez package (We can take inspiration from what I did in rez-pip).
  3. Run rez-env python -- jctest (We should rename it to something like __rez_install_test and make it output a JSON, or something like that).
  4. Check that the output of step 3 is <rez virtualenv root>/bin/python.
  5. Check that running python results in running Python from the rez package and not the rez install.

I think that this is enough to prove that our install is production ready and works as intended.

TO be even more sure, we could try to install with pip install --target and set PYTHONPATH to point to the rez lib. The rez commands should fail to run because -E prevents PYTHONPATH from being read by Python.

Eventually, we could review the flags used. -E gives us some guarantees, but we can provide even more guarantees by using other flags, like -I (which is is a combination of -E -P -s or we could make it more explicit with -E -s. -P is too new (but would be nice to have... It's only in 3.11). I think we could provide the same flags across all python versions we support).

Umm, it seems like it doesn't work when using pip install --target. But I don't think it's necessarily something we want to support...

I made good progress in the last 3 days. The launchers are now compiled from setup.py (only on Windows). I'm using the Zig compiler to compile the launcher, which means that MSVC isn't used and needed. There is now wheels for Windows x64 and Windows arm64. Other platforms are covered by a pure+universal wheel. I also added an integration test that uses a real rezified python package.

So far everything seems to be working great, except one test on Windows. It looks like rez-gui.exe isn't working. See https://github.com/AcademySoftwareFoundation/rez/actions/runs/6291958825/job/17080881978. It's probably something simple to fix.

There is one major limitation though, and it's that it doesn't support Python 2.

Questions still to be answered (they all have answers and are easy to answer):

  • Considering that Linux and macOS use the same wheel and Windows has its own wheels, how will rez-pip react? I'm asking because it's an uncommon situation.
  • What should we do with the install script? Should we keep it around? If so, should it use the new install method (it would simply do a pip install .) or should it still use the old install method (pip install . + dance for created the rez directory, etc)?
  • If we keep the install script, should we also keep the option to install as a rez package?
  • Do we want to compile the launchers on every build? It makes things easier, but it's also slower. Now that I use zig to build we can build the launchers on Linux while targeting Windows, so it's much easier to just commit the launchers in binary form.
  • Should we optimize the launchers for size or for performance? The default launchers created by pip are optimized for size. That's also what I did.
  • Considering that we have wheels on PyPI already and that right now they will install the CLI tools (even if they shouldn't), should we do a release just to remove the entry points (CLIs)? My concern is that we start to advertise that users can just pip install rez, and that they get an older version of rez in which it wasn't supported and they'd get bugs and problems all over the place...
  • Should we include the simple_launcher license in the wheel?

We should maybe try to support relative paths in the python stubs shebang to support cases like https://academysoftwarefdn.slack.com/archives/C0321B828FM/p1695737655931909. Pip would still produce absolute paths in the installed stubs, but at least users could modify them with a post-install script of their own to whip a more portable rez install (even if we don't officially support it).

I think this functionality is already supported by simple_launcher, but I'd have to double check to make sure it is really the case.

Codecov Report

Attention: Patch coverage is 86.56716% with 9 lines in your changes are missing coverage. Please review.

Project coverage is 58.36%. Comparing base (f63031e) to head (d3940c2). Report is 3 commits behind head on main.

Files Patch % Lines
src/rez/cli/_entry_points.py 92.98% 4 Missing :warning:
src/rez/system.py 50.00% 3 Missing :warning:
src/rez/shells.py 50.00% 2 Missing :warning:
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #1536      +/-   ##
==========================================
+ Coverage   58.30%   58.36%   +0.06%     
==========================================
  Files         126      126              
  Lines       17159    17142      -17     
  Branches     3505     3506       +1     
==========================================
+ Hits        10004    10005       +1     
+ Misses       6492     6475      -17     
+ Partials      663      662       -1     

:umbrella: View full report in Codecov by Sentry.
:loudspeaker: Have feedback on the report? Share it here.

codecov[bot] avatar May 04 '24 20:05 codecov[bot]