Skip to content

Add support for relative 'file:' requirements in pip_install #367

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 3 commits into from

Conversation

aaliddell
Copy link
Contributor

@aaliddell aaliddell commented Oct 3, 2020

PR Checklist

Please check if your PR fulfills the following requirements:

  • Does not include precompiled binaries, eg. .par files. See CONTRIBUTING.md for info
  • Tests for the changes have been added (for bug fixes / features)
  • Docs have been added / updated (for bug fixes / features)

PR Type

What kind of change does this PR introduce?

  • Bugfix
  • Feature (please, look at the "Scope of the project" section in the README.md file)
  • Code style update (formatting, local variables)
  • Refactoring (no functional changes, no api changes)
  • Build related changes
  • CI related changes
  • Documentation content changes
  • Other... Please describe:

What is the current behavior?

Issue Number: closes #366

Relative file: requirements do not work due to pip wheel being run from the generated repository root.

What is the new behavior?

Relative file: URIs in requirements.txt are converted to absolute file:/// URIs based on the directory containing the requirements.txt file. This allows wheel files within the workspace to take part in dependency resolution, since the alternative whl_library rule is both non-recommended and does not attempt to fetch dependencies based on the wheel metadata.

Supports both file:some/path/to/wheel.whl and requirement @ file:some/path/to/wheel.whl. If a requirement is already absolute it will not be altered. For this to work, the requirements.txt file has to be copied into the generated repository, since we do not want to amend the source file in place.

This does not attempt to support local wheels with paths specified without file:, since these are equivalent but the bare requirement is harder to patch. Supporting that version consistently would require either writing a full parser for the requirements.txt format or depending on the internal implementation in pip._internal.

Does this PR introduce a breaking change?

  • Yes
  • No

Other information

You may be able to deprecate whl_library rule as a result of this, if desired.

@aaliddell
Copy link
Contributor Author

I'm not sure how you'd like to test this, since we'd require having a .whl file (or other supported requirement type) checked into the repo, perhaps in the examples/pip_install folder. We could either choose to find a very small existing .whl file or create a tiny one ourselves. However, I can understand hesitation towards adding another binary file, since the .par files have been a pain to review in the past also.

Let me know what you'd like?

@pstradomski
Copy link
Contributor

pstradomski commented Oct 4, 2020 via email

@aaliddell
Copy link
Contributor Author

Unfortunately I don't think that can work easily, since the wheel has to exist at the time the repo rules are run. The wheel files created in that folder won't be present until much later when the execution phase has completed.

Since they are technically separate workspaces, you could get it to work in CI by forcing the test order and copying the wheel at the right point, but it would not be a portable solution that would work for any contributors machine.

@LouisStAmour
Copy link

LouisStAmour commented Feb 21, 2021

As an alternative to adding a binary .whl file, perhaps we could re-use a source folder with a very minimal setup.py file? For example https://github.com/maet3608/minimal-setup-py or see A/setup.py in https://github.com/LouisStAmour/rules_python-pip-cwd-bug

I came here with an alternative idea however. Since the problem with relative path resolution is that pip can resolve paths to other requirements.txt files relatively just fine, but that it can't resolve package paths to anything but the current working directly, what if we changed the current working directory?

https://github.com/bazelbuild/rules_python/blob/c639955c18bbc16e6a9e5228540b6151fd3b10b3/python/pip_install/pip_repository.bzl#L53-L61

Just add working_directory to the above, and give it the path to the requirements.txt file? Seems simpler than editing and rewriting the requirements.txt file and supports any new syntax that comes out. For bonus points, make the working_directory an optional parameter that can be overridden as necessary. Heck, if it's too complicated to figure out what working directory to use, I'd be very happy with an optional parameter that I could add to override current behaviour and specify a working directory. In my case, I'd like to be able to say it should execute within a subfolder.

Not sure if my suggestion for working_directory actually solves the above issue for .whl files as I don't have one of those. But I do want to use code from folder /A with a setup.py file as a module for folder /B yet my requirements.txt is expecting to run within a venv in folder /B from folder /B as the cwd. Works great that way, but doesn't work when running inside Bazel due to the different working directory. It resolves ./parent-requirements.txt from B/child-requirements.txt but it can't resolve ../A from B/parent-requirements.txt correctly.

Here's a repo that reproduces the above scenario exactly: https://github.com/LouisStAmour/rules_python-pip-cwd-bug

My suggestion would be to allow the following in WORKSPACE:

# I would like to be able to say:
pip_install(
    name = "b_deps",
    requirements = "//B:child-requirements.txt",
    working_directory = "B"
)
# ... or similar.

This would be like:

npm_install(
    name = "b_npm",
    package_json = "//B:package.json",
    package_path = "B",
    package_lock_json = "//B:package-lock.json",
)

where you can specify package_path to change the current working directory but it would eventually (in rules_nodejs 4.x) default to the location of package.json. It's not quite the same thing. In rules_nodejs, instead of setting the working_directory, the package_path is passed to index.js as an argument: https://github.com/bazelbuild/rules_nodejs/blob/a6449b7c7a4d4d8a733058504a060feb6bff10b8/internal/npm_install/npm_install.bzl#L165 which in turn captures the argument https://github.com/bazelbuild/rules_nodejs/blob/a6449b7c7a4d4d8a733058504a060feb6bff10b8/internal/npm_install/generate_build_file.ts#L62 and then a linker uses the path later from external_npm_package_path as described in bazel-contrib/rules_nodejs@2c2cc6e but ... it serves basically the same purpose. I have to admit I don't understand the difference between the simpler thing of doing an npm install where the CWD for npm install is the package_path vs doing ... whatever it is they're doing in rules_nodejs now to install packages. Presumably it's to get around node's strange package resolution or something. But luckily rules_python already supports multiple pip_installs, so the only thing missing is making sure pip has the right CWD, yes?

@aaliddell
Copy link
Contributor Author

I came here with an alternative idea however. Since the problem with relative path resolution is that pip can resolve paths to other requirements.txt files relatively just fine, but that it can't resolve package paths to anything but the current working directly, what if we changed the current working directory?

That may be suitable, I'll have to test. Provided we don't end up messing up where the outputs are written, but I think that's already managed IIRC.

As an alternative to adding a binary .whl file, perhaps we could re-use a source folder with a very minimal setup.py file? For example https://github.com/maet3608/minimal-setup-py or see A/setup.py in https://github.com/LouisStAmour/rules_python-pip-cwd-bug

Do you mean for the test or in general? For a test, any of the supported requirement types would be suitable, I just picked .whl as that's what I had in mind when working on this. I guess a non-binary file would be more palatable 👍

@aaliddell
Copy link
Contributor Author

Superceded by #433

@aaliddell aaliddell closed this Mar 8, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Support local wheel files in pip_install requirements.txt
4 participants