astral-sh / rye

a Hassle-Free Python Experience
https://rye.astral.sh
MIT License
13.82k stars 467 forks source link

Don't include the project in the lock file in favor of installing it implicitly by default #895

Open helderco opened 8 months ago

helderco commented 8 months ago

I suggested this in https://github.com/astral-sh/rye/discussions/239#discussioncomment-8802791, so I'm aware of:

Rather than needing the sed workaround to remove -e file:. from the lock file, I'd much prefer having the lock represent dependencies only and having Rye implicitly installing the current project in editable mode (for non-virtual projects).

Then have an option, similar to Poetry's --no-root, to not install the current project with the dependencies.

This way, the current workflow continues to work, workspaces still added as -e to the lock and that's fine, and there's an escape hatch for those that want to install dependencies seperately from the current project.

My use case for this is building a docker image, but I'm not using Rye there (only in dev). Just using uv directly in the container:

# copy only requirements.lock
uv install --no-deps -r requirements.lock
# copy all files
uv install --no-deps -e .
chainyo commented 8 months ago

My use case for this is building a docker image, but I'm not using Rye there (only in dev). Just using uv directly in the container:

# copy only requirements.lock
uv install --no-deps -r requirements.lock
# copy all files
uv install --no-deps -e .

Have you tried to use a simple linux image with minimal dependencies (like a slim one) and rely on rye + uv to install the python and the dependencies? If you defined a rye script to launch your app this looks like an amazing fast way to build a docker no?

Not to hijack this Issue as I think the possibility to do what you highlighted would be beneficial, but I'm also looking for the best/easiest/fastest way to build a Docker app with rye 🤗

helderco commented 8 months ago

I'm planning on trying that, but only in a specific case. The use case I mention above affects all users of a platform, so I need something more production-ready.

But I'm very interested in the fastest way to build a container that is able to run a python app. In this case speed is more important than disk space.

mitsuhiko commented 7 months ago

I think it might make sense to remove the packages themselves from the lock file. I'm not opposed to it, but I did not spend so much time thinking about the implications of that yet.

GeorchW commented 7 months ago

Okay, after playing around with building docker images for a bit, here's my humble opinion on this:

This is basically a trade-off: If you want all the dependencies and the project itself to be installed, the -e file:. in the lockfile is useful, since you can install it all in a single command. But if you don't want to install the project itself, you'll need to do weird sed hacks to do that.

Not having -e file:. in the lockfile means that you'll need a second command to install the package itself if you want it, which is a minor inconvenience. But you don't need any weird hacks to just install the dependencies, which is pretty nice.

During development, this doesn't matter, since people are going to use rye itself anyway. But when deploying, there are situations where you want to install the dependencies only. This is obviously the case when using docker to get better layer caching. But it also has advantages when installing the project on bare metal, since it allows you to do this:

pip install --no-deps -r requirements.lock
pip install --no-deps dist/my-project-name.whl # (needs to be pre-built obv.)

This avoids any (slow) dependency resolution and ensures that the dependencies are exactly the same as those that were locked. It also avoids having to install build dependencies on a production machine.

So yeah, I think it's a much more common case that people want to install dependencies only. But even if that's not the case, the inconvenience of typing pip install -e . if you want it is also much lower than typing sed -i '/^-e /d' *.lock if you don't.

noamraph commented 5 months ago

I just had to go through quite complex hoops in order to overcome the existing behavior. I want to use the requirements.lock file generated by rye as an input to Bazel's pip_parse in rules_python. It didn't work because of the -e file:. line, and I had to write a special "repository rule" in order to remove it.

So, just another reason for removing this from requirements.lock. I think that the lock file should only contain the dependencies, not extra lines which makes some uses of it more convenient and other uses much less convenient.

If anyone needs this and finds this comment, here's what I did: I added a file `fix_requirements.bzl`: ```python """ A repository rule for removing the `-e file:.` line which rye adds to requirements.lock """ def _fix_requirements_impl(rctx): requirements_lock = rctx.attr.requirements_lock src = rctx.read(requirements_lock) src_lines = src.split("\n") dst_lines = [line for line in src_lines if not line.startswith("-e ")] dst = "\n".join(dst_lines) rctx.file("BUILD.bazel", "") rctx.file("requirements.lock", dst, executable=False) fix_requirements = repository_rule( implementation = _fix_requirements_impl, attrs = { "requirements_lock": attr.label(allow_single_file = True), } ) ``` and then, in `WORKSPACE.bazel`, I wrote: ```python load("@rules_python//python:pip.bzl", "pip_parse") load("fix_requirements.bzl", "fix_requirements") fix_requirements(name="fixed_requirements", requirements_lock="//:requirements.lock") pip_parse( name = "my_deps", python_interpreter_target = interpreter, requirements_lock = "@fixed_requirements//:requirements.lock", ) ```
helderco commented 5 months ago

I'm planning on trying that, but only in a specific case. The use case I mention above affects all users of a platform, so I need something more production-ready.

Just an update on this. I did try using a small image, install rye and get Python through that but it took twice as long as getting the official slim Python. Adding rye to that slim adds overhead but uv via oci image is worth it.

RomainBrault commented 4 months ago

I can add a use case:

I want to use pip-audit (https://github.com/pypa/pip-audit) to check my dependencies using requirements.lock

pip-audit --disable-pip --requirement requirements.lock

does not work due to the line -e file: .

PushUpek commented 4 months ago

Another use case:

I want to utilise docker cache, to speed up CI pipeline

# install only deps
COPY pyproject.toml requirements.lock /app/
RUN rye sync --no-dev --no-lock --virtual

# install project
COPY src/ /app/src
RUN rye sync --no-dev --no-lock
thibautd commented 3 months ago

An other reason is that this -e file: . prevents installing dependencies using pip install --no-cache-dir -r requirements.lock in a Dockerfile if you used https://rye.astral.sh/guide/pyproject/#toolryegenerate-hashes !

In that case, you will get this error:

Obtaining file:///. (from -r requirements.lock (line 12)) ERROR: The editable requirement file:///. (from -r requirements.lock (line 12)) cannot be installed when requiring hashes, because there is no single file to hash.