Support multiplatform pexes with uv lockfiles. - #23427
Conversation
968088e to
80ad542
Compare
|
|
||
|
|
||
| @pytest.fixture | ||
| def complete_platform(rule_runner: PythonRuleRunner) -> bytes: |
There was a problem hiding this comment.
This fixture was unused even before my change.
d7c208c to
5414bb5
Compare
|
|
||
| @pytest.mark.platform_specific_behavior | ||
| @pytest.mark.parametrize("resolver", ["pex", "uv"]) | ||
| def test_create_lambda_from_lockfile(resolver: str, rule_runner: PythonRuleRunner) -> None: |
There was a problem hiding this comment.
Other tests were not using lockfiles but rather the legacy "resolve on demand without a lockfile" functionality. So this test is novel even in the pex case.
| extra_log_lines_base = tuple() if complete_platforms_target_type else (" Runtime: python37",) | ||
| expected_extra_log_lines = extra_log_lines_base + ( | ||
| expected_extra_log_lines = ( | ||
| " Runtime: python37", |
There was a problem hiding this comment.
Now we always compute the runtime python version, even if a complete_platforms is specified, because we don't yet know if we're using pex or uv.
ebf6a00 to
1cc2bb3
Compare
|
|
||
| Support for creating multiplatform/foreign platform pexes when using the `uv` resolver. This includes support for FAAS (AWS Lambda/Google Cloud Functions). | ||
|
|
||
| Support for remote caching/execution when using the `uv` resolver. |
There was a problem hiding this comment.
This was in a previous PR that was not in the release notes.
| reexported_handler_module=PythonAwsLambdaHandlerField.reexported_handler_module, | ||
| ) | ||
| ), | ||
| **implicitly(), |
There was a problem hiding this comment.
Needed because we added a PythonSetup arg to the callee
| target_name="unused", | ||
| runtime=TestRuntimeField("completely ignored!", address), | ||
| architecture=FaaSArchitecture.ARM64, # ignored | ||
| runtime=TestRuntimeField("3.45", address), |
There was a problem hiding this comment.
This is no longer ignored - it's used to compute uv_platform, even if that doesn't end up being used (because we're using pex resolution).
1cc2bb3 to
f582492
Compare
|
AI disclosure: Claude was used to help with some plumbing, but it was mostly unhelpful with my attempts to get it to be smarter. |
tobni
left a comment
There was a problem hiding this comment.
Every FaaS build materializes the entire resolve for that platform, so any partial-platform package anywhere in the resolve blocks unrelated targets.
Concretely for us: we build desktop apps for macOS & intel linux and lambdas for AL2023, and a lambda whose closure is 23 pure-python requirements fails to package because pyqt6-qt6 has no wheel for the lambda platform.
Pex just did "the right thing" by subsetting the lock per target. Here we'd need to enumerate platform markers in our requirements.txt so that install-time skipping kicks in. Workable, but users may need to be informed requirements.txt markers is how to get a build working.
Future:
Could the sync be restricted to the consumer's closure? uv.lock knows the package.dependencies graph and pants already knows the target's top-level requirements, so the complement could be excluded via --no-install-package at the cost of keying venvs by closure rather than by resolve+platform? Might be complicated but it would give us feature parity.
|
Another observation: (the empty uv.toml is on main, and #23454 only fixes uv lock) FaaS packaging uses sync and sync needs the indices. uv.lock stores registry urls without credentials, so uv sync needs the index config again. The venv rule writes an empty uv.toml, so generation works but every install 401s against our CodeArtifact index. Fix that works for us: resolve_config = await determine_resolve_config(
ResolveConfigRequest(metadata.resolve), **implicitly()
)
# snip
FileContent("uv.toml", resolve_config.uv_config().encode()), |
|
Will add that with my comments addressed using hacks I got this to run in our repo, which is exciting! |
|
I'll fix this up ASAP per your comments |
|
Thanks for the contribution. We've just branched for 2.33.x, so merging this pull request now will come out in 2.34.x, please move the release notes updates to docs/notes/2.34.x.md if that's appropriate. |
#23365 is an attempt in this direction. You can pass |
Does #23443 address this? |
No, the venv rule |
0f66277 to
780405e
Compare
|
@tobni this is ready for another look, and if you can try it out in your repo that would be great. The main thing not yet addressed is syncing just the closure of the needed requirements. That can be done separately. |
|
Yep, this works! I do think the closure feature is important to get in though. The Some findings while running:
InvalidTargetException: In the 'python_aws_lambda_function' target: Could not find a known runtime for the
inferred Python version and machine architecture!
* Python version: (3, 15) [inferred from interpreter constraints]
* Machine architecture: x86_64
...
To fix, please: - specify `uv_platforms` for the given machine architecture,
or specify a runtime that is known to Pants.This is not a feature we use, mind you. Our IC and lambda runtimes are lockstep.
|
Yeah, this is a little tricky - we also now must infer an interpreter version instead of allowing the ambient interpreter. I wonder if we should do the following heuristic: only change the behavior if |
|
Yeah that heuristic would catch that error. My thoughts
|
The lockfile format is the best source of truth, but we don't know it here, and changing that would mean pulling a lot of code inside out, which I really don't want to do.
We can detect this - if an explicit complete_platforms is provided then we refuse to infer a uv_platforms and fail later. |
|
Alternatively maybe the way to kill two birds with one stone and say that you cannot use |
Also supports building FaaS (awslambda/gcp cloud functions).
We leverage the fact that
uvcan create foreign-platform venvswith the
--python-platformflag. It still needs a local pythoninterpreter of the appropriate version, but it downloads and installs
wheels for the foreign platform. Of course there must be foreign
platform wheels available for all distributions. If there isn't one for
some dist, uv will build from the sdist for the local platform, which
may lead to a later runtime error.
Will close #23339